最近復習了一下多線程的知識
作用差不多,側重點不一樣
臨界區: 共享資源
互斥對象 線程間的同步
事件對象:一般用在比較復雜的地方,能夠傳遞一些信息
下面是互斥對象、事件對象和關鍵代碼段的比較:
1互斥對象
[cpp]
#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;
}
#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事件對象
[cpp]
#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;
}
#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關鍵代碼段
[cpp]
#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;
}
#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函數怎麼還能運行的?
使用互斥對象,顯示的結果有時候會是這樣。百思不得其解。