最近复习了一下多线程的知识
作用差不多,侧重点不一样
临界区: 共享资源
互斥对象 线程间的同步
事件对象:一般用在比较复杂的地方,能够传递一些信息
下面是互斥对象、事件对象和关键代码段的比较:
1互斥对象
#include <iostream> #include <windows.h> using namespace std; // 声明两个线程函数 DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ); DWORD WINAPI ThreadProc2( LPVOID lpParameter // thread data ); // 全局票数 int gTicket = 100; // 互斥对象 HANDLE hMutex; int main() { // 创建两个线程句柄 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); // 创建互斥对象 hMutex = CreateMutex(NULL, false, NULL); // 关闭两个线程句柄 CloseHandle(hThread1); CloseHandle(hThread2); // 主线程睡4秒,方便两个线程函数能够获取CPU时间片 Sleep(4000); system("pause"); return 0; } // 定义两个线程函数 DWORD WINAPI ThreadProc1(LPVOID lpParameter ) { while(true) { WaitForSingleObject(hMutex, INFINITE); if(gTicket > 0) { cout<<"thread1 sell ticket "<<gTicket--<<endl; } else { break; } ReleaseMutex(hMutex); } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParameter ) { while(true) { WaitForSingleObject(hMutex, INFINITE); if(gTicket > 0) { cout<<"thread2 sell ticket "<<gTicket--<<endl; } else { break; } ReleaseMutex(hMutex); } return 0; }
2事件对象
#include <Windows.h> #include <iostream> using namespace std; // 声明两个线程函数 DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ); DWORD WINAPI ThreadProc2( LPVOID lpParameter // thread data ); // 全局变量 int gTicket = 100; // 事件对象 HANDLE hEvent; int main() { // 创建两个线程句柄 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); // 创建时间对象 hEvent = CreateEvent(NULL, false, true, NULL); // 关闭两个线程句柄 CloseHandle(hThread1); CloseHandle(hThread2); // 主线程睡4秒,让别的线程函数有机会获得CPU时间片 Sleep(4000); system("pause"); return 0; } // 定义两个线程函数 DWORD WINAPI ThreadProc1(LPVOID lpParameter ) { while(true) { WaitForSingleObject(hEvent, INFINITE); if(gTicket > 0) { cout<<"thread1 sell ticket "<<gTicket--<<endl; } else { break; } SetEvent(hEvent); } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParameter ) { while(true) { WaitForSingleObject(hEvent, INFINITE); if(gTicket > 0) { cout<<"thread2 sell ticket "<<gTicket--<<endl; } else { break; } SetEvent(hEvent); } return 0; }
3关键代码段
#include <iostream> #include <windows.h> using namespace std; // 声明两个线程函数 DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ); DWORD WINAPI ThreadProc2( LPVOID lpParameter // thread data ); // 全局票数 int gTicket = 100; // 关键代码段 CRITICAL_SECTION gSection; int main() { // 初始化关键代码段,必须先于线程的创建 InitializeCriticalSection(&gSection); // 创建两个线程句柄 HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL); // 关闭两个线程句柄 CloseHandle(hThread1); CloseHandle(hThread2); // 主线程sleep 4秒 Sleep(4000); // 删除关键代码段 DeleteCriticalSection(&gSection); system("pause"); return 0; } // 定义两个线程函数 DWORD WINAPI ThreadProc1(LPVOID lpParameter ) { while(true) { EnterCriticalSection(&gSection); // 进入关键代码段 if(gTicket > 0) { cout<<"thread1 sell ticket "<<gTicket--<<endl; } else { break; } LeaveCriticalSection(&gSection); // 离开关键代码段 } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParameter ) { while(true) { EnterCriticalSection(&gSection); // 进入关键代码段 if(gTicket > 0) { cout<<"thread2 sell ticket "<<gTicket--<<endl; } else { break; } LeaveCriticalSection(&gSection); // 离开关键代码段 } return 0; }
程序运行的结果,相信大家都已经很清楚了,但是,前面两个内核对象(互斥对象、事件对象)的结果有点出乎意料。
以事件对象为例。用断点调试,竟然发现了这样的问题。线程1的函数获取互斥对象的拥有权(并未释放拥有权),接着切换CPU时间片,进入到了线程2函数的WaitForSingleObject,然后调用了线程2函数的 cout<<"thread2
sell ticket "<<gTicket--<<endl;,这是怎么一回事呢,线程1函数还未释放拥有权,线程2函数怎么还能运行的?
使用互斥对象,显示的结果有时候会是这样。百思不得其解。
希望大侠能点明一下在下。给点意见。