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