cHANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //安全描述符 BOOL bManualReset, //设置信号复位方式为自动恢复为无信号状态(FALSE)还是手动恢复为无信号状态(TRUE) BOOL bInitialState, //初始状态,创建出来时,是不是有信号 LPCTSTR lpName //信号名称,可以为Null );
cDWORD WINAPI ThreadProc_1(LPVOID lpParameter) { TCHAR szBuf[10] = {0}; //当时间变成已通知 WaitForSingleObject(g_hEvent,INFINITE); //线程执行 printf("ThreadProc_1执行了\r\n"); getchar(); return 0; } DWORD WINAPI ThreadProc_2(LPVOID lpParameter) { TCHAR szBuf[10] = {0}; //当时间变成已通知 WaitForSingleObject(g_hEvent,INFINITE); //线程执行 printf("ThreadProc_2执行了\r\n"); getchar(); return 0; } int main() { //创建事件 //默认安全属性,TRUE通知/FALSE互斥,初始没信号,没名字 //通知类型时,两个线程都会执行 //互斥类型时,必须一个执行完,才能执行另一个 //通知类型时,WaitForSingleObject不修改状态为占用 //互斥类型时,WaitForSingleObject修改状态为占用 g_hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); HANDLE hThread[2]; //创建两个进程 hThread[0] = CreateThread(NULL,0,ThreadProc_1,NULL,0,NULL); hThread[1] = CreateThread(NULL,0,ThreadProc_2,NULL,0,NULL); //设置事件为已通知,修改Event状态 SetEvent(g_hEvent); //等待线程结束,销毁内核对象 WaitForMultipleObjects(2, hThread, TRUE, INFINITE); CloseHandle(hThread[0]); CloseHandle(hThread[1]); CloseHandle(g_hEvent); return 0; }
<1> 线程互斥:线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排
它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去
使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
<2> 线程同步: 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依
赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时
才被唤醒。
同步 = 互斥 + 有序
互斥的问题就是,执行完进程A,接着执行的不一定是进程B,有可能依然是进程A
有序的意思就是,进程A和进程B,一边执行一次,轮流执行
c// 生产.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // # include <windows.h> # include <stdio.h> HANDLE hMutex; int g_Max = 10; //生产几个产品 int g_Number = 0; //容器 存储产品,可以看做是临界资源,一定是互斥的 //生产者线程函数 DWORD WINAPI ThreadProduct(LPVOID pM) { for (int i = 0; i < g_Max; i++) { //互斥的访问缓冲区 WaitForSingleObject(hMutex, INFINITE); if (g_Number == 0) { g_Number = 1; //将全局变量改成1 DWORD id = GetCurrentThreadId(); //获取当前执行的线程ID printf("生产者%d将数据%d放入缓冲区\r\n", id, g_Number); } else { //如果不符合if条件,那就返回i的次数,不能浪费本次循环 i--; } ReleaseMutex(hMutex); } return 0; } //消费者线程 DWORD WINAPI ThreadConsumer(LPVOID pM) { for (int i = 0; i < g_Max; i++) { //互斥的访问缓冲区 WaitForSingleObject(hMutex, INFINITE); if (g_Number == 1) { g_Number = 0; //将全局变量改回0 DWORD id = GetCurrentThreadId(); printf("-----消费者%d将数据%d放入缓冲区\r\n", id, g_Number); } else { //如果不符合if条件,那就返回i的次数,不能浪费本次循环 i--; } ReleaseMutex(hMutex); } return 0; } int main() { //创建一个互斥体 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); WaitForMultipleObjects(2, hThread, TRUE, INFINITE); CloseHandle(hThread[0]); CloseHandle(hThread[1]); //销毁 CloseHandle(hMutex); return 0; }
以上代码表面上看起来没问题,但是会有一定的浪费,因为,进入for循环之后,进入else,会浪费for多余的次数
c// 生产.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // # include <windows.h> # include <stdio.h> HANDLE g_hSet,g_hClear; int g_Max = 10; //生产几个产品 int g_Number = 0; //容器 存储产品,可以看做是临界资源,一定是互斥的 //由于g_hSet初始值有信号的,所以WaitForSingleObject能够得到信号 //所以g_Number = 1; //开始生产 //生产结束后,调用SetEvent来修改g_hClear变成有信号的 //由于当前的 g_hSet = CreateEvent(NULL, FALSE, TRUE, NULL); g_hSet对象是FALSE是互斥的,所以一执行WaitForSingleObject就将g_hSet状态给修改成0了,所以此时即使再次执行生产者线程也无法执行,就会开始执行消费者线程 //生产者线程函数 DWORD WINAPI ThreadProduct(LPVOID pM) { for (int i = 0; i < g_Max; i++) { WaitForSingleObject(g_hSet, INFINITE); g_Number = 1; //将全局变量改成1 DWORD id = GetCurrentThreadId(); //获取当前执行的线程ID printf("生产者%d将数据%d放入缓冲区\r\n", id, g_Number); SetEvent(g_hClear); //一旦执行SetEvent,就把自己线程挂起了,不会再执行剩余次数,通知别人可以执行了 } return 0; } //由于生产者线程执行完之后将g_hClear状态改为了有信号,所以WaitForSingleObject能够得到信号 //所以g_Number = 0; //开始消费 //消费结束后,调用SetEvent来修改g_hSet变成有信号的 //由于当前的 g_hClear = CreateEvent(NULL, FALSE, FALSE, NULL); g_hClear对象是FALSE是互斥的,所以一执行WaitForSingleObject就将g_hClear状态给修改成0了,所以此时即使再次执行消费者线程也无法执行,就会开始执行生产者线程 //消费者线程 DWORD WINAPI ThreadConsumer(LPVOID pM) { for (int i = 0; i < g_Max; i++) { WaitForSingleObject(g_hClear, INFINITE); g_Number = 0; //将全局变量改成0 DWORD id = GetCurrentThreadId(); //获取当前执行的线程ID printf("-----消费者%d将数据%d放入缓冲区\r\n", id, g_Number); SetEvent(g_hSet); //一旦执行SetEvent,就把自己线程挂起了,不会再执行剩余次数,通知别人可以执行了 } return 0; } int main() { HANDLE hThread[2]; //安全描述符,互斥,有信号的,名字(不写),给生产者线程用的 g_hSet = CreateEvent(NULL, FALSE, TRUE, NULL); //安全描述符,互斥,无信号的,名字(不写),给消费者线程用的 g_hClear = CreateEvent(NULL, FALSE, FALSE, NULL); hThread[0] = ::CreateThread(NULL, 0, ThreadProduct, NULL, 0, NULL); hThread[1] = ::CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL); WaitForMultipleObjects(2, hThread, TRUE, INFINITE); CloseHandle(hThread[0]); CloseHandle(hThread[1]); //销毁 CloseHandle(g_hSet); CloseHandle(g_hClear); return 0; }
本文作者:Na1r
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!