线程的同步(一)---临界区

当多个线程访问一个独占性共享资源时,可以使用临界区对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。

以下的临界区用法中,CRITICAL_SECTION一般是在SDK下使用,而CCriticalSection类是MFCCRITICAL_SECTION使用的封装。如果是在MFC下编程,推荐使用CCriticalSection类。

1 使用CRITICAL_SECTION结构

使用方法:

      CRITICAL_SECTION g_cs;

      EnterCriticalSection(&g_cs);

      ……         //要加锁的代码段

      LeaveCriticalSection(&g_cs);

1) 该结构的使用有两个要求:

第一个要求是,需要访问该资源的所有线程都必须知道负责保护资源的CRITICAL_SECTION结构的地址,你可以使用你喜欢的任何机制来获得这些线程的这个地址;

第二个要求是, CRITICAL_SECTION结构中的成员应该在任何线程试图访问被保护的资源之前初始化。该结构通过调用下面的函数来进行初始化:

void InitializeCriticalSection(PCRITICAL_SECTION pcs);

该函数用于对(pcs指向的)CRITICAL_SECTION结构的各个成员进行初始化。由于该函数只是设置了某些成员变量。因此它的运行不会失败,并且它的原型采用了void的返回值。该函数必须在任何线程调用EnterCriticalSection函数之前被调用。Platform SDK的文档清楚地说明,如果一个线程试图进入一个未初始化的CRITICAL_SECTION,那么结果将是很难预计的。当知道进程的线程不再试图访问共享资源时,应该通过调用下面的函数来清除该CRITICAL_SECTION结构:

void DeleteCriticalSection(PCRITICAL_SECTION pcs);

DeleteCriticalSection函数用于对该结构中的成员变量进行删除。当然,如果有任何线程仍然使用关键代码段,那么不应该删除该代码段。同样, Platform SDK文档清楚地说明如果删除了关键代码段,其结果就无法知道。

2) EnterCriticalSection负责进行下列测试:

如果没有线程访问该资源,EnterCriticalSection便更新成员变量,以指明调用线程已被赋予访问权并立即返回,使该线程能够继续运行(访问该资源)。

• 如果成员变量指明,调用线程已经被赋予对资源的访问权,那么EnterCriticalSection便更新这些变量,以指明调用线程多少次被赋予访问权并立即返回,使该线程能够继续运行。这种情况很少出现,并且只有当线程在一行中两次调用EnterCriticalSection而不影响对LeaveCriticalSection的调用时,才会出现这种情况。

• 如果成员变量指明,一个线程(除了调用线程之外)已被赋予对资源的访问权,那么EnterCriticalSection将调用线程置于等待状态。这种情况是极好的,因为等待的线程不会浪费任何CPU时间。系统能够记住该线程想要访问该资源并且自动更新CRITICAL_SECTION的成员变量,一旦目前访问该资源的线程调用LeaveCriticalSection函数,该线程就处于可调度状态。

 

2 使用MFCCCriticalSection

1)定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如:

         CCriticalSection critical_section

2)在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()函数获得临界区对象:

         critical_section.Lock();

在线程中调用该函数来使线程获得它所请求的临界区。如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。

3)访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:

         critical_section.Unlock();

 

 

 

你可能感兴趣的:(线程的同步(一)---临界区)