linux临界区原理,临界区的实现原理

linux临界区原理,临界区的实现原理临界区概述 用于多线程的互斥访问 如果有多个线程试图同时访问临界区 那么在有一个线程进入临界区后 其他试图访问的线程将被挂起 直到进入临界区的线程离开 临界区在被释放后 其他线程可以继续抢占 并以此达到对临界区的互斥访问 临界区中一般都是一个简短的代码段 在 WINDOWS 中 临界区是一种应用层的同步对象 非内核对象 并且临界区优先采用自旋的方式进行抢占临界区 API 临界区初始化以及删除 Init

临界区概述:

用于多线程的互斥访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入临界区后,其他试图访问的线程将被挂起,直到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到对临界区的互斥访问。(临界区中一般都是一个简短的代码段)

在WINDOWS中,临界区是一种应用层的同步对象,非内核对象。并且临界区优先采用自旋的方式进行抢占

临界区API:

临界区初始化以及删除:

InitializeCriticalSection()

DeleteCriticalSection()

临界区两个操作原语:

EnterCriticalSection()

LeaveCriticalSection()

临界区数据结构:

typedef struct _RTL_CRITICAL_SECTION {

PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

//

// The following three fields control entering and exiting the critical

// section for the resource

//

LONG LockCount;

LONG RecursionCount;

HANDLE OwningThread; // from the thread’s ClientId->UniqueThread

HANDLE LockSemaphore;

ULONG_PTR SpinCount; // force size on 64-bit systems when packed

} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

_RTL_CRITICAL_SECTION_DEBUG数据结构

typedef struct _RTL_CRITICAL_SECTION_DEBUG {

WORD Type;

WORD CreatorBackTraceIndex;

struct _RTL_CRITICAL_SECTION *CriticalSection;

LIST_ENTRY ProcessLocksList;

DWORD EntryCount;

DWORD ContentionCount;

DWORD Flags;

WORD CreatorBackTraceIndexHigh;

WORD SpareWORD ;

} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; (代码来自VS2005 WINNT.h)

_RTL_CRITICAL_SECTION 各字段解释:

DebugInfo:指向一个调试用的数据,该结构的类型为RTL_CRITICAL_SECTION_DEBUG

LockCount: 初始值-1,若结果大于等于0,表示该临界区已被线程占用。

OwningThread: 当前拥有临界区的线程

RecursionCount:所有者线程连续进入临界区的次数

LockSemaphore: 内核对象句柄,用于告知操作系统,该临界区目前处于空闲状态,用于唤醒因等待临界区而挂起的线程

SpinCount:MSDN对该字段做如下解释:

“On multiprocessor systems, if the critical section is unavailable, the calling thread will spin

dwSpinCount times before performing a wait operation on a semaphore associated with the critical

section. If the critical section becomes free during the spin operation, the calling thread

avoids the wait operation.”

在多处理器系统中,如果临界区已被占用,那么线程就自旋SpinCount次去获取临界区,而不是通过阻塞等待的方式去获取临界区。如果在自旋的过程中临界区空间,就可以直接进入临界区,减少等待时间(如果进入等待状态,需要用户态内核态的切换,代价较大)。主要意思就是为了提高效率,下面我们会分析什么叫自旋。

临界区API实现过程

InitialzeCriticalSection 在初始化的过程中,会测试CPU的数量,若CPU数量为1,则忙等待没有意义。则SpinCount=0,

若CPU数量大于1,则设置SpinCount,在进入临界区时,会采取主动进入策略。

EnterCriticalSection 1. 若临界区还未被占用,则更新临界区数据结构,表示调用线程已经获得访问临界区的权限,返回。

2. 若线程在已经获取访问权限的情况下,再次EnterCriticalSection,则更新线程获取访问的次数(即连续Enter的次数)。

3. 若临界区已经其他线程占用,则当前线程 通过SpinCount来控制忙等的次数,在SpinCount已经等于0还没有获得临界区对象的情况下,函数直接通过临界区对象内部的事件对象进行等待(等待及唤醒涉及到用户态和内核态的切换,不是最优方案,优先采用自旋的方式进入临界区)。忙等待是通过对LockCount进行原子读写操作实现。

RtlLeaveCriticalSection 1. _RTL_CRITICAL_SECTION数据结构中相关标志位设置 ,比如RecursionCount–,如果为0,表示没有线程占用临界区

2. 将当前占有线程句柄设为0,表示现在临界区目前处于有信号状态,可以被获取

3. 若有其他线程在等待,唤醒等待线程

a3a35f2f9e608518c70933d4e14c1235.gif

通过该数据结构可以发现,在进程中,所有的临界区的DEBUG信息通过链表进行串接。在已知某个临界区对象的

情况下, 通过链表数据结构,可以访问到数据的临界区对象。

自旋:

对于临界区的操作,(EnterCriticalSection)操作,采用的是主动进入临界区。意思就是,当没有能够进入时,不停的主动尝试进入,直至进入为止。这种主动进入的方式,称为自旋(也叫忙等待)。

被动方式:获取不到后,进入等待队列,当要获取的对象被释放后,系统唤醒等待的线程,这个方式叫做被动方式。

小结:

1.进入灵界区和离开临界区是成对操作,进入临界区必须要有离开临界区否则临界区保护的共享资源将永远不会被释放。

2.在使用临界区时,临界区间使用的代码最好简短,减少其他线程的等待时间,提高程序性能。

3.临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

4. 临界区是用户态下的对象,非内核对象,所以在使用时无需再用户态和内核态之间切换,效率明显要比其他用户互斥的内核对象高。

参考:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/217730.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午8:54
下一篇 2026年3月18日 上午8:54


相关推荐

  • 了解大数据的技术生态系统 Hadoop,hive,spark(转载)

    了解大数据的技术生态系统 Hadoop,hive,spark(转载)

    2022年1月7日
    45
  • Springboot导出Excel并下载[通俗易懂]

    Springboot导出Excel并下载[通俗易懂]一、引入相关依赖<!–数据导出excel–><!–https://mvnrepository.com/artifact/org.apache.poi/poi–>

    2022年8月16日
    7
  • 关于Pytorch中双向LSTM的输出表示问题

    关于Pytorch中双向LSTM的输出表示问题在使用pytorch的双向LSTM的过程中,我的大脑中蒙生出了一个疑问。双向的lstm的outputs的最后一个状态与hidden,两者之间肯定有所联系,但具体是什么样子的呢?会不会hidden状态存储的就是outputs的最后一个状态,这样的话,岂不是会导致hidden并不能表示整个序列的双向信息吗?带着这个疑问,我开始了实验。具体的实验代码,这里就不放了。直接放实验结果吧。output_size:torch.Size([14,32,100])hidden_size:torch.S

    2022年6月22日
    70
  • java语法分析器_JavaCC语法分析器

    java语法分析器_JavaCC语法分析器JavaCC JavaCompiler 是 Java 实现的语法分析器 用以根据用户自定义规则进行上下文无关语法内容的分析工作 以简化编译器开发时编写涉及词法 语法 语义规则处理代码时的工程量 较之 C 语言实现的简化编译构造程序 LEX LexicalAnaly 和 YACC YetAnotherCo JavaCC 使用递归下降的语法分析方法 定义的

    2026年3月18日
    2
  • 【JS】不同发布地址页面跳转[通俗易懂]

    【JS】不同发布地址页面跳转[通俗易懂]在使用html+json构建页面时,页面的跳转常用location.href完成当然,也有些直接在a标签的href中完成本来很简单的事,但是发布方式不同,就会一起一些问题,主要是页面路径跳转问题===========================================================列如,制作了两个网站html,同时放在WebSite这个文件夹下这两个网站都是一样的目录…

    2022年5月22日
    49
  • JAVA四舍五入保留一位小数

    JAVA四舍五入保留一位小数newBigDecimal(speed).setScale(1,BigDecimal.ROUND_HALF_UP).doubleValue()

    2022年5月11日
    58

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号