Windows核心编程 - 用内核对象进行线程同步

        在上一篇文章Windows核心编程-用户模式下的线程同步中已总结了用户模式下的几种同步机制,它们的特点就是速度快,但也有些局限性。那么与用户模式的同步机制相对的,可以使用内核对象进行同步,既然是内核对象,那么就涉及到用户模式与内核模式切换,所以内核对象同步机制的缺点是会有性能问题,但它们的用途会更广一些,例如可以实现进程间的同步。

        同步,其实是一方A需要感知另一方B的状态,以便采取相应的措施(是继续在此等待呢还是开始往下执行)。对于线程、进程等内核对象来说,它们要么是处理触发状态,要么处理未触发状态。 Microsoft为每种对象创建了一些规则,规定如何在这两种状态之间进行切换。线程或进程内核对象在创建的时候总是处理未触发状态,当线程或进程终止时,状态才改为触发。而且当状态变成触发后,将永远保持这种状态,不会再回到未触发状态。因此,可以通过调用一个等待函数,由系统来检查目标内核对象的状态,当状态发生变化时等待函数返回,调用方检查返回结果,采取进一步的措施,以实现同步。

1. 事件内核对象

       事件内核对象是比较简单的一种,它内部有一个用来表示是自动重置事件还是手动重置事件的布尔值,以及一个用来表示事件有没有被触发的布尔值。有两种类型的事件对象:手动重置事件和自动重置事件,两者区别:

        1)当一个手动重置事件被触发时,正在等待该事件的所有线程都会变成可调度状态。

        2)当一个自动重置事件被触发时,只会有一个正在等待该事件的线程变成可调度状态,如果有多个正在等待该事件的线程,则不确定是哪一个线程会变成可调度状态。

       把事件变成触发状态,使用SetEvent(); 把事件变成未触发状态,使用ResetEvent()。

      事件最通常的用途是:让一个线程执行初始化工作,然后再触发另一个线程,让它执行剩余的工作。

2.信号量内核对象

        信号量内核对象用来对资源进行计数,与其它内核对象不同的是它内部有两个32位值:一个是最大资源计数,另一个是当前可用资源计数。最大资源计数表示信号量可以控制的最大资源数量,当前可用资源计数表示信号量当前可用资源的计数。

        信号量的规则如下:

        1)如果 当前可用资源计数大于0, 那么信号量处于触发状态;

         2)如果当前可用资源计数等于0,那么信号量处于未触发状态;

         3)系统绝对不会让当前可用资源计数变为负数;

         4)当前可用资源计数绝对不会大于最大资源计数。

         信号量最大的优势是会以原子方式来对资源计数进行检查及设置操作。比方说,当向信号量请求一个资源时,系统会检查资源是否还够,如果资源足够,则将可用资源计数递减,整个过程不会被其它线程打断。

         应用: 多线程访问共享资源的数量有限制的,可考虑使用信号量机制。

3.互斥量内核对象

         互斥量内核对象用于确保一个线程对一个资源的独占访问。它内部包含一个线程ID和一个递归计数。线程ID用于标识 当前占用这个互斥量的是哪个线程,递归计数表示这个线程占用该互斥量的次数。

         互斥量与关键段的行为类似,但是互斥量比关键段要慢,因为它需进入到内核模式。但互斥量可以实现进程间的同步,即不同进程中的线程可以访问同一个互斥量。

         互斥量的规则:

        1)如果线程ID为0(无效线程ID),那么该互斥量不为任何线程所占用,它处于触发状态;

        2)如果线程ID为非零值,那么有一个线程已经占用了该互斥量,它处于未触发状态;

        应用:一般用来对多个线程访问的同一块内存进行保护。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章