criticalsection函数怎么使用(critical的用法归纳)

背景阅读开源代码的时候,非常多的场合会看到EnterCriticalSection和LeaveCriticalSection成对的出现,它们是代表什么意思呢,为啥见到Enter就一定会有leave成对。

criticalsection函数怎么使用(critical的用法归纳)critical section是翻译是临界截面,临界区的意思。多线程间的通信有四个方法,包括临界区,互斥量,信号量,事件。我看了网上很多博客,似乎把critical section和互斥量搞混了,很多博客里说critical section是互斥量,准确来讲这是一个互斥变量不是互斥量。临界区critical section和互斥体mutex的区别windows都支持临界区和互斥体,linux只支持互斥体;互斥体可以用于对象进程间或线程间的互斥访问,可以理解为多进程的多线程互斥访问,但是临界区只能用于同一进程里线程间的互斥访问;互斥体是内核对象,在核态进行锁操作,速度慢;临界区是非内核对象,只在用户态进行锁操作,速度快;注意了,多线程间通信最快的是临界区critical section是每个线程中访问临界资源的那段代码,不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。

主要api以及使用方式在windows sdk里它的接口是放在synchapi.h(syn是同步的意思,也就是临界区是用来调度多线程的同步问题)以及WinBase.h头文件里,包括以下几个主要api,其实也就是初始化和释放临界区资源,每次的进入临界区和离开临界区,非常好记。同时需要谨记的是,它一个临界区最多管理64个线程,也就是线程数量多了超过了它的范畴,就会产生后果,至于后果我倒没尝试碰过。

EnterCriticalSection和LeaveCriticalSection是成对调用的,很多同学大部分会碰到的问题就是死锁的问题了。临界区内有return,break,continue,go等等跳转,一不小心就会造成死锁,因此,很多开源代码里包括我们自己的项目工程中,主程架构者都会对critical section进行封装。比如以下巧妙的将critical section封装在类里,利用类的构造函数和析构函数对应初始化临界区和释放临界区资源,加锁和解锁对应进入临界区和离开临界区,这样也刚好避开了那么长的api函数名称。

线程进入临界区的调度原则多线程进入临界区是要遵循调度规则的,正如当交通拥堵时,这个时候红绿灯可能也不管用,只能是警察出现调度车辆,在路口协调,而司机们必须按照交接的部署协调完成操作。这个时候有人会问,如果不遵循调度规则会怎么样,很明显你能得到一个结果但可能不是你想要的,因为这个时候混乱了。如果有若干线程要求进入空闲的临界区,一次仅允许一个线程进入。任何时候,处于临界区内的线程不可多于一个。如已有线程进入自己的临界区,则其它所有试图进入临界区的线程必须等待。临界区能管理的极限是64个线程,所以临界区使用场景被用于线程数量不多的情况下进入临界区的线程要在有限时间内退出,以便其它线程能及时进入自己的临界区。如果线程不能进入自己的临界区,则应让出CPU,避免线程出现“忙等”现象。对于加了同一种锁的线程,只能依次执行,不许同步执行,但是对于不加锁或者加了不同锁的线程,可以同步执行。(这里的加锁可以参照上面的api使用方式,其实就是封装了临界区的锁)总结这个使用其实是比较简单易接受的,所以导致了很多程序员使用线程同步的第一思路都会坚持采用这个方式,比如多线程写个log啊,多线程记录datareport上报啊等等,它不需要去对内存进行修改,速度快,算是轻骑兵的方式。但同时不能进行内核模式操作也导致了它的缺点暴露。生活不仅只有代码,还有诗和远方。

发表评论

登录后才能评论