CreateEvent函数使用记录
最近在写一个串口对话框程序,使用到了CreateEvent函数。于是就特地谷歌了一番。
总体感觉就是CreateEvent相当于创建了一个信号灯,在A线程里面点灯(SetEvent),在B线程中观察等待(WaitForSingleObject),看到灯亮了就开始干活。
创建信号灯的时候:
- 可以设定信号灯是否人工(手动)关闭(CreateEvent的第二个参数),TRUE为手动关闭,FALSE为自动关闭。
- 可以设定信号灯的初始状态(CreateEvent的第三个参数)为TRUE或者FALSE。
所谓的人工关闭,就是程序员在合适的地方主动调用ResetEvent来关闭信号灯。
而信号灯的状态决定了WaitForSingleObject是否可以结束等待,如果为TRUE则结束等待,否则根据WaitForSingleObject的最后一个参数来决定等待多久。
对于一个线程,不可能即观察一个灯的状态,同时又自己来对这个灯进行点灯、灭灯操作,这样做没有任何意义。
总结信号灯的使用需要涉及如下五点:
- 创建信号灯。调用CreateEvent,要与CloseHandle成对使用。
- 创建观察信号灯的线程。
- 设置信号灯的状态。就是点灯了,把灯点亮,告诉需要观察这个灯状态的线程注意干活。
- 复位信号灯的状态。取决于创建信号灯的时候是否人工复位。
- 删除信号灯。调用CloseHandle来删除,等于是释放内存。
为此,写了如下一段测试代码。主要就是两个线程和两个信号灯:
- 填充线程。功能是观察fillable信号灯,当fillable灯亮之后,就灭fillable灯,然后往全局buffer里面填充数据,再点亮fetchable灯。
- 拉取线程。功能是观察fetchable信号灯,当fetchable灯亮之后,就灭fetchable灯,接着从全局buffer里面读取数据,最后再点亮fillable灯。
对于信号灯的初始化(CreateEvent函数的第三个参数),自然是fillable要初始化为亮灯状态,fetchable要初始化为灭灯状态。很自然地,没有数据你怎么去fetch嘛,所以必然要先fill,后fetch,这就是这两个信号灯的初值了。
对于主线程中的 WaitForMultipleObjects 函数,顾名思义,自然就是等待多个信号条件都满足的时候才会结束等待,这与我们在新开线程中使用的WaitForSingleObject算是一对兄弟了。所以主线程中创建两个子线程以后,不能自己直接结束了,应该要调用WaitForMultipleObjects来等待两个子线程的结束,然后删除信号灯,要不然可能内存泄露。
// createevent.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <stdio.h> #include <string.h> static HANDLE mEventHandle_fillable; static HANDLE mEventHandle_fetchable; static char mSharedBuffer[128] = {0}; static const char *stop_keyword = "\r\nSTOP\r\n"; static DWORD WINAPI fill_thread(LPVOID lpParam) { int i = 0; while(WAIT_OBJECT_0 == WaitForSingleObject( mEventHandle_fillable, INFINITE)) { if (i < 3) { sprintf_s(mSharedBuffer, sizeof(mSharedBuffer), "%d", i); ResetEvent(mEventHandle_fillable); printf("Please fetch your data.\n"); SetEvent(mEventHandle_fetchable); } else { strcpy_s(mSharedBuffer, sizeof(mSharedBuffer), stop_keyword); ResetEvent(mEventHandle_fillable); printf("Fill finish. We can have a rest.\n"); SetEvent(mEventHandle_fetchable); break; } i++; } printf("fill_thread exit with code 0, last error=%d\n", GetLastError()); return 0; } static DWORD WINAPI fetch_thread(LPVOID lpParam) { while(WAIT_OBJECT_0 == WaitForSingleObject( mEventHandle_fetchable, INFINITE)) { if (0 == strcmp(mSharedBuffer, stop_keyword)) { ResetEvent(mEventHandle_fetchable); printf("\nGot. We must have a rest!\n"); } else { printf("fetched \"%s\".\n", mSharedBuffer); mSharedBuffer[0] = 0; ResetEvent(mEventHandle_fetchable); Sleep(3000); printf("Please fill.\n\n"); SetEvent(mEventHandle_fillable); } } printf("fetch_thread exit with code 0, last error=%d\n", GetLastError()); return 0; } static void test_entry(void) { static HANDLE threads[2]; DWORD tid; mEventHandle_fillable = CreateEvent(NULL, TRUE, TRUE, TEXT("fillable")); mEventHandle_fetchable = CreateEvent(NULL, TRUE, FALSE, TEXT("fetchable")); threads[0] = CreateThread(NULL, 0, fill_thread, NULL, 0, &tid); threads[1] = CreateThread(NULL, 0, fetch_thread, NULL, 0, &tid); WaitForMultipleObjects(2, threads, TRUE, INFINITE); CloseHandle(mEventHandle_fillable); CloseHandle(mEventHandle_fetchable); } int _tmain(int argc, _TCHAR* argv[]) { test_entry(); printf("\n\n***\npress ENTER key to exit!\n"); getchar(); return 0; }
测试截图截图

代码逻辑图

参考:https://docs.microsoft.com/en-us/windows/win32/sync/using-event-objects
原文:https://www.cnblogs.com/ssdq/p/13157077.html