1.通知类型
该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。
参数说明:
lpEventAttributes 一般为NULL
bManualReset 创建的Event是自动复位还是人工复位.如果true,人工复位, 一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号. 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位,变成无信号. 如果想 在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件 的信号。
bInitialState 初始状态,true,有信号,false无信号
lpName 事件对象的名称。您在OpenEvent函数中可能使用。
1 // 事件.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <windows.h> 6 7 8 HANDLE g_hEvent; 9 10 DWORD WINAPI ThreadPro_1(LPVOID IpParameter) 11 { 12 TCHAR szBuffer[10] = { 0 }; 13 14 //当事件变成已通知时 15 WaitForSingleObject(g_hEvent,INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号 16 //线程执行 17 printf("ThreadPro_1执行了\n"); 18 getchar(); 19 20 return 0; 21 } 22 DWORD WINAPI ThreadPro_2(LPVOID IpParameter) 23 { 24 TCHAR szBuffer[10] = { 0 }; 25 26 //当事件变成已通知时 27 WaitForSingleObject(g_hEvent, INFINITE);//一直等待信号 28 //线程执行 29 printf("ThreadPro_2执行了\n"); 30 getchar(); 31 SetEvent(g_hEvent); 32 33 return 0; 34 } 35 int main() 36 { 37 //创建事件 38 //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字 39 g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 40 HANDLE hThread[2]; 41 //创建两个线程 42 hThread[0] = CreateThread(NULL, 0, ThreadPro_1, NULL, 0, NULL); 43 hThread[1] = CreateThread(NULL, 0, ThreadPro_2, NULL, 0, NULL); 44 45 //设置事件为已通知 46 SetEvent(g_hEvent); 47 48 49 //等待线程结束,销毁内核对象 50 WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕 51 CloseHandle(hThread[0]); 52 CloseHandle(hThread[1]); 53 CloseHandle(g_hEvent); 54 55 56 return 0; 57 }
2.线程同步
同步的前提是互斥。
同步 = 互斥 + 有序
下面用生产者消费者问题来做个阐述:
// 生产者消费者问题.cpp : 定义控制台应用程序的入口点。 // //只能互斥不能实现同步 #include "stdafx.h" #include <windows.h> HANDLE hMutex; int g_Max = 10; //生产几个产品 int g_Number = 0; //容器 存储产品 DWORD WINAPI ThreadProduct(LPVOID IpParameter) { for (int i =0 ; i<g_Max;i++) { //互斥的访问缓冲区 //当事件变成已通知时 WaitForSingleObject(hMutex, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号 g_Number = 1; DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID printf("生产者%d将数据%d放入缓冲区\n", id, g_Number); ReleaseMutex(hMutex); } return 0; } DWORD WINAPI ThreadConsumer(LPVOID IpParameter) { for (int i = 0; i < g_Max; i++) { //互斥的访问缓冲区 //当事件变成已通知时 WaitForSingleObject(hMutex, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号 g_Number = 0; DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID printf("消费者%d将数据%d放入缓冲区\n", id, g_Number); ReleaseMutex(hMutex); } return 0; } int main() { //创建事件 //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字 hMutex = CreateMutex(NULL, FALSE ,NULL); HANDLE hThread[2]; //创建两个线程 hThread[0] = CreateThread(NULL, 0, ThreadProduct, NULL, 0, NULL); hThread[1] = CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL); getchar(); //等待线程结束,销毁内核对象 WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕 CloseHandle(hThread[0]); CloseHandle(hThread[1]); CloseHandle(hMutex); return 0; }
改良后利用事件实现同步:
1 // 生产者消费者问题.cpp : 定义控制台应用程序的入口点。 2 // 3 //只能互斥不能实现同步 4 #include "stdafx.h" 5 #include <windows.h> 6 7 8 HANDLE g_hSet,g_hClear; 9 10 int g_Max = 10; //生产几个产品 11 int g_Number = 0; //容器 存储产品 12 DWORD WINAPI ThreadProduct(LPVOID IpParameter) 13 { 14 for (int i =0 ; i<g_Max;i++) 15 { 16 //互斥的访问缓冲区 17 //当事件变成已通知时 18 WaitForSingleObject(g_hSet, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号 19 g_Number = 1; 20 DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID 21 printf("生产者%d将数据%d放入缓冲区\n", id, g_Number); 22 SetEvent(g_hClear);//生产者执行完后放开消费者的信号 23 } 24 25 26 return 0; 27 } 28 DWORD WINAPI ThreadConsumer(LPVOID IpParameter) 29 { 30 for (int i = 0; i < g_Max; i++) 31 { 32 //互斥的访问缓冲区 33 //当事件变成已通知时 34 WaitForSingleObject(g_hClear, INFINITE);//一直等待信号 如果事件的第二参数为FALSE则必须运行完后,在放开信号 35 //执行完后自动将信号设置为0; 36 g_Number = 0; 37 DWORD id = GetCurrentThreadId();//获取当前正在执行线程的ID 38 printf("消费者%d将数据%d放入缓冲区\n", id, g_Number); 39 SetEvent(g_hSet);//消费者执行完后放开生产者的信号 40 } 41 42 43 return 0; 44 } 45 int main() 46 { 47 //创建事件 48 //默认安全属性 TRUE 通知/FALSE互斥 初始没信号 没有名字 49 g_hSet = CreateEvent(NULL,FALSE, TRUE ,NULL); //生产者初始有信号 50 g_hClear = CreateEvent(NULL, FALSE, FALSE, NULL); 51 HANDLE hThread[2]; 52 //创建两个线程 53 hThread[0] = ::CreateThread(NULL, 0, ThreadProduct, NULL, 0, NULL); 54 hThread[1] = ::CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL); 55 56 57 getchar(); 58 //等待线程结束,销毁内核对象 59 WaitForMultipleObjects(2, hThread, TRUE, INFINITE);//等待两个线程都运行完毕 60 CloseHandle(hThread[0]); 61 CloseHandle(hThread[1]); 62 CloseHandle(g_hSet); 63 CloseHandle(g_hClear); 64 65 return 0; 66 }