《VC++深入详解–学习笔记》(16)线程同步

Filed Under (VC++ 学习笔记) by panmaoru on 22-12-2009

上一章介绍了线程同步,以及利用互斥对象实现线程同步的方法。本章继续介绍另2种线程同步的方法:事件对象和关键代码段,另外,介绍了利用异步套接字编写网络应用程序的实现。

16.1事件对象

和互斥对象一样,时间对象也属于内核对象。事件对象分为人工重置的事件对象和自动重置的事件对象。人工重置的事件对象得到通知时,等待该事件对象的所有线程都变为可调度线程。自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个变为可调度线程。

HANDLE CreateEvent(

  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD

  BOOL bManualReset,                       // reset type

  BOOL bInitialState,                      // initial state

  LPCTSTR lpName                           // object name

);

根据事件对象的声明可以了解它的一些参数属性。创建一个事件对象之后,可以通过SetEvent函数和ResetEvent函数来设置事件对象的有无信号状态。通常在单CPU平台下,为了实现线程的通过,常使用自动重置的事件对象,而非人工重置的事件对象。

16.2关键代码段

关键代码段:也称为临界区,工作在用户态,它是指一个小段代码,在代码能够执行前,它必须独占对某些资源的访问权。通常把多线程中访问同一种资源的那部分代码称为关键代码段。利用关键代码段实现线程同步的示例代码如下:

#include <windows.h>

#include <iostream.h>

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

int ticket=100;

CRITICAL_SECTION g_cs;

void main()

{

       HANDLE hThread1;

       HANDLE hThread2;

       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

       CloseHandle(hThread1);

       CloseHandle(hThread2);

       InitializeCriticalSection(&g_cs);//初始化

       Sleep(4000);

       DeleteCriticalSection(&g_cs);

}

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

       while(TRUE)

       {

              EnterCriticalSection(&g_cs);//进入关键代码段

              Sleep(1);

              if(ticket>0)

              {

                     Sleep(1);

                     cout<<"thread1 sell the ticket:"<<ticket--<<endl;

                     LeaveCriticalSection(&g_cs);//离开

              }

              else

              {

                     LeaveCriticalSection(&g_cs);//离开

                     break;

              }

       }

       return 0;

}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

       while(TRUE)

       {

              EnterCriticalSection(&g_cs);//进入关键代码段

              Sleep(1);

              if(ticket>0)

              {

                     Sleep(1);

                     cout<<"thread2 sell the ticket:"<<ticket--<<endl;

                     LeaveCriticalSection(&g_cs);//离开

              }

              else

              {

                     LeaveCriticalSection(&g_cs);//离开

                     break;

              }

       }

       return 0;

}

16.3互斥对象,事件对象和关键代码段的比较

  • 互斥对象和事件对象属于内核对象,速度较慢,但是使用这样的内核对象,可以在多个进程中的各个线程间进行同步;
  • 关键代码段工作在用户态,速度快。但是使用关键代码段时容易产生死锁,因为在等待进入关键代码段时候无法设定超时值。

Post a comment