三.事件
前两个技术都属于加锁技术,即两个线程互斥的时候使用,那么线程也会有协调工作的时候,这时候就需要用到我们的事件和信号量了。
- 相关问题:
多线程协调工作的时候的通知问题 - 事件的使用
- 创建事件:
使用CreatEvent
函数,MSDN官方解释
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性 BOOL bManualReset, //事件重置/复位方式 BOOL bInitialState, //事件初始状态 LPCSTR lpName //为事件命名 );
- 参数解释:
- bManualReset为事件重置/复位方式,如果该参数被设置为TRUE那么就需要我们来手动重置事件对象,如果该参数被设置为FALSE,那么操纵系统会帮我们完成事件的重置和复位。
- bInitialState:该参数指定了当创建事件后,该事件句柄是否处于有消息状态
- 等候事件:
WaitFor......
函数 - 触发事件(使事件句柄处于有消息状态)
BOOLSetEvent( HANDLE hEvent );
- 复位事件(将事件句柄设置为无消息状态)
BOOL ResetEvent( HANDLE hEvent );
- 关闭事件
CloseHandle
函数
我们来看看事件的使用:
#include <stdio.h> #include <windows.h> DWORD WINAPI ThreadProc1(LPVOID lpParameter); DWORD WINAPI ThreadProc2(LPVOID lpParameter); DWORD g_value = 0; HANDLE hEvent = NULL; //用于接收事件句柄 int main() { DWORD nID = 0; HANDLE hThread[2] = { 0 }; hEvent = CreateEvent(NULL,FALSE,0,NULL); hThread[0] = CreateThread(NULL, 0, ThreadProc1, NULL, 0, &nID); hThread[1] = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &nID); WaitForMultipleObjects(2, hThread, TRUE, INFINITE); printf("%d\n", g_value); CloseHandle(hEvent); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParameter) { char a[] = "********"; while (1) { WaitForSingleObject(hEvent, INFINITE); for (int i = 0; i < strlen(a); i++) { printf("%c", a[i]); } printf("\n"); ResetEvent(hEvent); } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParameter) { while (1) { Sleep(1000); SetEvent(hEvent); } return 0; }
这是一个很典型的相互协调工作的双线程,我们在A线程中没有设定时间间隔,但是在B线程中设定了事件间隔,我们能够很明显地感受到输出是有时间间隔的:
四.信号量
- 相关问题:
类似于事件,解决线程之间通知的相关问题,但提供一个计数器,可以设置次数。 - 创建信号量:
使用CreateSemaphore
函数:
MSDN官方解释
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUIES lpSemaphoreAttributes, //安全属性 LONG lInitialCount, //初始化信号量数量 LONG lMaximumCount, //信号量的最大值 LPSTSTR lpName //为信号量命名 );创建成功返回信号量句柄
- 等候信号量
使用WaitFor...
函数
注意: 等候每通过一次,信号量的信号减一,知道为0阻塞 - 给信号量指定定计数值
使用ReleaseSemaphore()
函数
MSDN官方解释
BOOL ReleaseSemaphore( HANDLE hSeamephore, //信号量句柄 LONG lReleaseSemaphore, //信号量将增加的量 LPONG lpPreviousCount //指向一个变量的指针,用于记录信号量的上一个计数 );
- 关闭信号量:
使用CloseHandle()
函数
我们来看看信号量的使用实例:
#include <stdio.h> #include <windows.h> DWORD WINAPI ThreadProc1(LPVOID lpParameter); DWORD WINAPI ThreadProc2(LPVOID lpParameter); HANDLE hSemaphore = NULL; //用于接收事件句柄 int main() { DWORD nID = 0; HANDLE hThread[2] = { 0 }; hSemaphore = CreateSemaphore(NULL, 3, 10, NULL); hThread[0] = CreateThread(NULL, 0, ThreadProc1, NULL, 0, &nID); while (getchar()=='\n') { ReleaseSemaphore(hSemaphore, 5, NULL); } CloseHandle(hSemaphore); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParameter) { char a[] = "********"; while (1) { WaitForSingleObject(hSemaphore, INFINITE); for (int i = 0; i < strlen(a); i++) { printf("%c", a[i]); } printf("\n"); } return 0; }
我们设置了计数器为3的信号量,我们发现程序最开始只会输出三行,每当我们按一次回车键,就将信号量计数值值为5:
本篇文章的分享就到这里,如果大家发现有错误之处,还请大家指出来,我会非常虚心地学习。希望我们共同进步!!!