一、事件
1、创建事件
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);
参数: lpEventAttributes:指向SECURITY_ATTRIBUTES结构体的指针,
如果其值为NULL,则使用默认的安全性。
bManualReset:指定创建的是人工重置事件对象,还是自动重
置事件对象。如果是人工重置对象,当线程等
待到该对象的所有权限之后,需要调用ResetEvent
函数手动地将该事件设置为无信号状态;如果是自动
重置事件对象,当线程等到该对象的所有权之后,
系统会自动将该对象设置为无信号状态。
bInitialState: 指定事件对象的初始状态,如果此参数值为真,
那么该事件对象初始是有信号状态,否则是无
信号状态。
lpName: 指定事件对象的名称,如果此参数为NULL,
那么将创建一个匿名的事件对象。
2、设置事件对象状态
SetEvent函数将把指定的事件对象设置为有信号状态,该函数的原型如下:
BOOL SetEvent(HANDLE hEvent); 该参数指定将要设置其状态的事件对象的句柄。
3、重置事件对象状态
ReseEvent函数将把指定的事件对象设置为无信号状态,该函数的原型如下:
BOOL ResetEvent(HANDLE hEvent); 该参数指定将要重置其状态的事件对象句柄。
如果成功返回非0.否则返回0.
4、使用事件对象实现线程同步
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
总结:当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变
成为可调度线程;当一个自动重置的事件对象得到通知时,等待该事
件对象的线程中只有一个线程变为可调度线程,同时操作系统会将该
事件对象设置为无信号状态,这样,当对所保护的代码执行完成后,
需要调用SetEvent函数将该事件对象设置为有信号状态,而人工重置
的事件对象,在一个线程得到该事件对象之后,操作系统并不会将该
事件对象设置为无信号状态,除非显式地调用ReseEvent函数将其设置
为无信号状态,否则该对象会一直是有信号状态。
5、保证应用程序只有一个实例运行
g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");
if(g_hEvent)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
二、临界区
1、相关函数
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
2、实例
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_cs;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
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(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while(TRUE)
{
EnterCriticalSection(&g_cs);
Sleep(1);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket:"<<tickets--<<endl;
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
三、线程死锁
对多线程来说,人工线程1拥有了临界区对象A,等待临界区对象B的拥有权,
线程2拥有了临界区对象B,等待临界区对象A的拥有权,这就造成了死锁。
四、互斥,事件,临界的比较
1、互斥对象和事件对象都属于内核对象,利用内核对象进行线程同步时,
速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多进
程中的各个线程间进行同步。
2、临界在用户方式下,同步速度较快,但是使用临界时,很容易进入死
锁状态,因为在等待进入临界时无法设定超时值。
五、基于消息的异步套接字
1、相关函数说明
指定的套接字请求基于Windows消息的网络事件通知,并自动将该套接字
设置为非阻塞模式。
int WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg, long lEvent);
参数: s: 标识请求网络事件通知的套接字描述符。
hWnd: 标识一个网络事件发生时接收消息的窗口的句柄。
wMsg: 指定网络事件发生时窗口将接收到的消息。
lEvent: 指定应用程序感兴趣的网络事件。
第九节 线程的同步
原创
©著作权归作者所有:来自51CTO博客作者rosehacker2010的原创作品,请联系作者获取转载授权,否则将追究法律责任
上一篇:第八节 多线程基本知识
下一篇:第十节 进程间通信
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
【CSS】第九讲:CSS基本选择器(1)
本文讲了部分CSS选择器
选择器 属性值 基本语法 -
第九节TypeScript number
可表示的最小的数,即最接近 0 的正数 (实际上不会变成 0)。最大的负数是 -MIN_VALUE,MIN_VALUE 的值约为 5e-324。小于 MIN_VALUE ("unde
typescript javascript 前端 字符串 数字转换 -
第九节JavaScript 函数的定义与使用
当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。
javascript 开发语言 ecmascript html 函数表达式 -
【浙大 | 嵌入式系统】第九节
基于FPGA的嵌入式设计基础
嵌入式硬件 硬件描述语言 逻辑系统
















