最近在写一个串口对话框程序,使用到了CreateEvent函数。于是就特地谷歌了一番。
总体感觉就是CreateEvent相当于创建了一个信号灯,在A线程里面点灯(SetEvent),在B线程中观察等待(WaitForSingleObject),看到灯亮了就开始干活。
创建信号灯的时候:
所谓的人工关闭,就是程序员在合适的地方主动调用ResetEvent来关闭信号灯。
而信号灯的状态决定了WaitForSingleObject是否可以结束等待,如果为TRUE则结束等待,否则根据WaitForSingleObject的最后一个参数来决定等待多久。
对于一个线程,不可能即观察一个灯的状态,同时又自己来对这个灯进行点灯、灭灯操作,这样做没有任何意义。
总结信号灯的使用需要涉及如下五点:
为此,写了如下一段测试代码。主要就是两个线程和两个信号灯:
对于信号灯的初始化(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