[windows][thread] 同步.非内核.CriticalSection

概述    
       保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

       临界区:在所有同步对象中,临界区是最容易使用的,但它只能用于同步单个进程中的线程。取得对某个数据区的访临界区一次只允许一个线程问权。还有,在这些同步对象中,只有临界区不是内核对象,它不由操作系统的低级部件管理,而且不能使用句柄来操纵,由于不是内核对象,使得它作为一种轻量级的同步机制,同步速度比较快。

  

使用步骤:

 

1.       在进程中创建一个临界区,即在进程中分配一个CRITICAL_SECTION数据结构,该临界区结构的分配必须是全局的,这样该进程的不同线程就能访问它。关于CRITICAL_SECTION结构体的深入分析,可以参见文章:

      <<Break Free of Code Deadlocks in Critical Sections Under Windows>>

2.       在使用临界区同步线程之前,必须调用InitializeCriticalSection来初始化临界区。在释放资源之前,只需要初始化一次。

3.        VOID EnterCriticalSection:阻塞函数。The function returns when the calling thread is granted ownership。换言之,调用线程不能获取指定临界区的所有权时,该线程将睡眠,且在被唤醒之前,系统不会给它分配CPU。或者使用TryEnterCriticalSection方法尝试进入临界区,如果进入成功,则调用者线程获得临界区的使用权,否则返回失败。

4.         执行临界区内的任务

5.         BOOL LeaveCriticalSection:非阻塞函数。将当前线程对指定临界区的引用计数减壹;在使用计数变为零时,另一等待此临界区的一个线程将被唤醒。

6.         当不需要再使用该临界区时,使用DeleteCriticalSection来释放临界区需要的资源。此函数执行后,再也不能使用EnterCriticalSectionLeaveCriticalSection,除非再次使用InitializeCriticalSection初始化了该临界区。

 
注意事项:

1.   临界区一次只允许一个线程访问,每个线程必须在视图操作临界区域数据之前调用该临界区域标志(即一个CRITICAL_SECTION全局变 量)EnterCriticalSection后,其它想要获得访问权的线程都会置于睡眠状态,且在被唤醒以前,系统将停止为它们分配CPU时间片。换言之,临界区可以且仅可被一个线程拥有,当然,没有任何线程调用EnterCriticalSection或TryEnterCriticalSection时,临界区不属于任何 一个线程。

2.     当拥有临界区所有权的线程调用LeaveCriticalSection放弃所有权时,系统只唤醒等待队列中的一个线程,给它所有权,其它线程则继续等待。

3.     注意,拥有该临界区的线程,每一次针对此临界区的EnterCriticalSection调用都会成功(这里指的是重复调用也会立即返回,也就是支持嵌套调用),且会使得临界区标志(即一个CRITICAL_SECTION全局变量)的引用计数增加1。在另一个线程能够拥有该临界区之前,拥有它的线程必须调用LeaveCriticalSection足够多次,在引用计数降为零后,另一线程才有可能拥有该临界区。换言之,在一个正常使用临界区的线程中,calSection和LeaveCriticalSection应该成对使用

4.     TryEnterCriticalSection
BOOL TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );
从函数声明便可看出端倪,EnterCriticalSection函数的返回值为VOID,而这里为BOOL。可见对于TryEnterCriticalSection的调用,需要我们判断其返回值。在调用TryEnterCriticalSection时,如果指定的临界区没有被任何线程(或还没有被任何调用线程)拥有,该函数将临界区的访问权给予调用的线程,并返回TRUE;不过,如果临界区已经被另一个线程拥有,它立刻返回FALSE值。TryEnterCriticalSectionEnterCriticalSection之间的最大区别在于TryEnterCriticalSection从来不挂起线程。

posted @ 2011-06-21 15:09  zsounder  阅读(576)  评论(0编辑  收藏  举报