Window多线程同步(事件)
2017-12-25 14:53
106 查看
概述
事件是内核对象,用于线程间通信和同步。事件分为无信号状态和有信号状态,无信号状态会阻塞到WaitForSingleObject()函数,直到触发事件(即调用SetEvent)。有信号状态则会忽略事件触发信号,不会阻塞到WaitForSingleObject()函数。相关API
ResetEvent(), WaitForSingleObject(), CreateEvent(),SetEvent()函数原型
WINBASEAPI DWORD WINAPI WaitForSingleObject(_In_ HANDLE hHandle,
_In_ DWORD dwMilliseconds);
功能:等待事件被触发
参数:hHandle:事件句柄
dwMilliseconds:等待时间,一般设为INFINITE,意为永久阻塞,直到事件被触发。
如果设为IGNORE则函数立即返回,忽略信号
函数原型
WINBASEAPI _Ret_maybenull_ HANDLE WINAPI CreateEventA(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
_In_ BOOL bManualReset,
_In_ BOOL bInitialState,
_In_opt_ LPCSTR lpName
);
功能:创建事件
参数:lpEventAttributes:表示安全控制,一般直接传入NULL。
bManualReset:判断事件是否手动切换到无信号状态,为true,则需要手动切换,为false,则会自动切换。当调用SetEvent()触发事件时,WaitForSingleObject()就会返回,如果为手动切换,那么必须调用ResetEvent()使事件变成无信号状态,这样下次循环到WaitForSingleObject()函数时就会阻塞,否则WaitForSingleObject()函数会立即返回。果为自动切换,WaitForSingleObject()函数则会自动调用ResetEvent()。
bInitialState:表示事件的初始状态,TRUR表示已触发。
lpName: 事件的名称,NULL表示匿名事件
返回值:事件的句柄
函数原型
ResetEvent()
功能:事件设置成无信号状态
参数:hEvent 事件句柄
函数原型
SetEvent BOOL WINAPI SetEvent(_In_
HANDLE hEvent);
功能:事件触发
参数:hEvent 事件句柄
源码一
HANDLE g_Event = NULL; unsigned int __stdcall ChildThread(PVOID pM) { int i = (int)pM; char c = (char)(i + 65); while (true) { WaitForSingleObject(g_Event, INFINITE);//等待事件被触发 printf("%c同学抢到电影票,看电影去了\n", c); } return 0; } unsigned int __stdcall ChildThreadFunc(PVOID pM) { while (true) { Sleep(1000); printf("发送事件 \n"); SetEvent(g_Event); //触发事件 } return 0; }
int main() { HANDLE handles[5] = { 0 }; HANDLE handle = 0; g_Event = CreateEvent(NULL, FALSE, FALSE, NULL); for (int i = 0; i < 5; i++) { handles[i] = (HANDLE)_beginthreadex(NULL, 0, ChildThread, (void*)i, 0, NULL); } handle = (HANDLE)_beginthreadex(NULL, 0, ChildThreadFunc, NULL, 0, NULL); for (int i = 0; i < 3; i++) { WaitForSingleObject(handles[i], -1); } WaitForSingleObject(handle, -1); //释放线程句柄 for (int i = 0; i < 3; i++) { CloseHandle(handles[i]); } CloseHandle(handle); //删除事件 CloseHandle(g_Event); getchar(); return 0; }
结果
程序中共创建了6个线程,其中一个线程会调用SetEvent()触发事件,其他5个线程阻塞等待,当事件触发后等待的五个线程中的一个会解除阻塞,执行程序。每触发一次,只能使一个线程解除阻塞。由于操作系统实现了一定的公平性,使每个线程都能得到事件触发,从而使结果看起来比较合理。
源码二
HANDLE g_Event = NULL; unsigned int __stdcall ChildThread(PVOID pM) { int i = (int)pM; char c = (char)(i + 65); while (true) { Sleep(1000); WaitForSingleObject(g_Event, INFINITE);//等待事件被触发 printf("%c同学抢到电影票,看电影去了\n", c); ResetEvent(g_Event); } return 0; } unsigned int __stdcall ChildThreadFunc(PVOID pM) { while (true) { Sleep(1000); printf("发送事件 \n"); SetEvent(g_Event); //触发事件 } return 0; } int main() { HANDLE handles[5] = { 0 }; HANDLE handle = 0; g_Event = CreateEvent(NULL, TRUE, FALSE, NULL); for (int i = 0; i < 5; i++) { handles[i] = (HANDLE)_beginthreadex(NULL, 0, ChildThread, (void*)i, 0, NULL); } handle = (HANDLE)_beginthreadex(NULL, 0, ChildThreadFunc, NULL, 0, NULL); for (int i = 0; i < 3; i++) { WaitForSingleObject(handles[i], -1); } WaitForSingleObject(handle, -1); //释放线程句柄 for (int i = 0; i < 3; i++) { CloseHandle(handles[i]); } CloseHandle(handle); //删除事件 CloseHandle(g_Event); getchar(); return 0; }
结果
相对于源码一,源码二只修改了极少的地方,在调用CreateEvent时第二个参数由false改成了true。并在子线程中加了ResetEvent(),其实就是设置成了手动切换事件状态。但结果却大不相同。每触发一次事件,阻塞在子线程上的事件会全部解除阻塞,而不是触发一次,解除一个。但结果不是想象中的那样,出现了事件触发一次,3个子线程在运行,另外两个没有运行?
其实事件只有在等待时才会被接收(执行到WaitForSingleObject),在程序中每个子线程运行都需要一定的时间,当事件触发时,其中三个线程执行完毕阻塞到WaitForSingleObject等待事件,其他两个正在执行,还未正常等待,所以这两个线程就无法接受到事件,而且事件也不会保存,这就导致了以上的结果。
相关文章推荐
- jquery trigger伪造a标签的click事件取代window.open方法
- IE6中window.onresize事件的处理
- PB菜单带参数调用父窗口&父datawindow事件或函数
- 通过window.showModalDialog弹出的窗口中的GridView,如何触发翻页事件?
- JS 滚动事件window.onscroll与position:fixed写兼容IE6的回到顶部组件
- 非模态的titlewindow,点击外部时的事件
- PopupWindow进阶用法——android上实现类似UCweb的自定义menu,完全模拟系统事件
- 第5天(就业班) BOM、window对象、事件、location对象、screen对象、Dom编程根据属性找节点、通过关系找节点、添加附件、联动框、操作元素的css样式、正则表达式
- Window、document、form(属性、方法、事件)
- $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法
- $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法
- 使用jquery模拟键盘事件,但window系统并不会真的响应事件,只是浏览器当前页面会响应而已
- 多线程同步——互斥、事件、临界区区别
- Window和Document对象的事件
- Window.onLoad 和 DOMContentLoaded事件的先后顺序
- 如何在父窗口中得知window.open()出的子窗口关闭事件
- jquery trigger伪造a标签的click事件取代window.open方法
- 关于window的resize事件
- window.onload事件处理程序 innerHTML属性
- easyui window弹窗获取x事件