《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