C++ 多線程2 beginthread 啟動線程知識 20131021
Reference: http://blog.csdn.net/laoyang360/article/details/7720656
前言:
之前曾經使用過WINAPI創建線程並且啟動的知識,還有線程之間同步的知識,這里講解一下使用__beginthread的原理和機制。
1._beginthread 簡單的介紹
如果我們編寫的是C++的程序,不應該使用CreateThread WINAPI接口去創建線程,而是應該使用Visual C++運行庫函數_beginthread,退出線程的時候應該使用_endthread。因為_beginthreaex和_endthreadex是CRT的線程函數,所以必須注意編譯選項runtimelibrary,使用的是MT或者是MTD(MultiThreaded,debug Multithread);_beginthread函數的參數列表和CreateThread的參數列表完全相同,但是參數名稱和類型不是完全的相同。因為Microsoft的C/C++運行庫的開的小組認為C/C++運行期函數不應該對Windows數據類型有任何的依賴。
每一個線程都會獲得由C/C++運行期庫的堆棧分配自己的tiddata內存結構;傳遞給_beginthreadex的線程函數的地址保存在tiddata內存數據塊,傳遞給該函數的參數也保存在該數據塊中;_beginthreadex確實從內部調用CreateThread函數,因為這是創建線程早OS層面上的唯一的方法;當調用CreateThread函數的時候,他會被告知通過調用_threadstartex而不是pfnStartAddr來啟動執行新的線程,還有傳遞給線程函數的從哪回溯是tiddata結構而不是pvParam的地址;如果一切順利的話,就會像CreateThread那樣返回線程句柄,任何操作失敗就會返回NULL。
總的來說就是_beginthreadex在內部調用CreateThread函數,在調用之前_beginthreadex做了很多的工作,從而比CreateThread更加安全.
#include <iostream>
#include <string>
#include <process.h>
#include <Windows.h>
using namespace std;
class ThreadX{
private:
int loopStart;
int loopEnd;
int dispFrequency;
public:
string threadName;
ThreadX(int startVal, int endVal, int frequency){
this->loopStart = startVal;
this->loopEnd = endVal;
this->dispFrequency = frequency;
}
static unsigned __stdcall ThreadStaticEntryPoint(void * pThis){
ThreadX* pThX = (ThreadX*) pThis;
pThX->ThreadEntryPoint();
return 1;
}
void ThreadEntryPoint(){
for (int i = loopStart; i <= loopEnd; i++){
cout << threadName << " i = " << i << endl;
Sleep(100);
}
}
};
int main(){
ThreadX * pThX = new ThreadX(0, 10, 2000);
HANDLE hth1 = NULL;
unsigned uiThread1ID;
hth1 =(HANDLE) _beginthreadex(NULL,
0,
ThreadX::ThreadStaticEntryPoint,
pThX,
CREATE_SUSPENDED,
&uiThread1ID);
if (hth1 == NULL){
cout << "failed to create thread 1" << endl;
}
DWORD dwExitCode;
GetExitCodeThread(hth1, &dwExitCode); // shoule be STILL_ACTIVE
cout << "init thread 1 exit code id = " << dwExitCode << endl;
pThX->threadName = "yang1";
ThreadX* pThX2 = new ThreadX(0, 10, 2000);
HANDLE hth2 = NULL;
unsigned uiThread2ID;
hth2 = (HANDLE) _beginthreadex(NULL,
0,
ThreadX::ThreadStaticEntryPoint,
pThX2,
CREATE_SUSPENDED,
&uiThread2ID);
if (hth2 == NULL){
cout << "create thread 2 failed" << endl;
}
GetExitCodeThread(hth2, &dwExitCode);
cout << "init thread 2 exit code id = " << dwExitCode << endl;
pThX2->threadName = "yang2";
ResumeThread(hth1);
ResumeThread(hth2);
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
GetExitCodeThread(hth1, &dwExitCode);
cout << "thread 1 exited with exit code " << dwExitCode << endl;
GetExitCodeThread(hth2, &dwExitCode);
cout << "thread 2 exited with exit code " << dwExitCode << endl;
CloseHandle(hth1);
CloseHandle(hth2);
delete pThX;
delete pThX2;
pThX = NULL;
pThX2 = NULL;
cout << "end program " << endl;
return 0;
}
2.線程臨界區
線程之間共享的對象,當修改的時候,只能夠一個線程修改,同時不存在其他的線程訪問該資源,這就是線程之間的同步問題.在上一篇總結中使用的是CreateMutex函數創建一個HANDLE,這樣的話創建一個Mutex,當線程訪問資源的時候,使用WaitForSimpleObject(handl, INFINITE);獲得該對象的鎖,然后再使用完的時候,釋放對象鎖,ReleaseMutex(handle);
在線程中有一個概念是臨界區,在C++中使用這一種實現的,就是用CRITICAL_SECTION 聲明一個臨界區變量,然后再程序開始的時候,使用InitializeCriticalSelection(CRITICAL_SELECTION*) 初始化臨界變量,然后當線程進入臨界區的時候,使用EneterCriticalSelection(CRITICAL_SELECTION*);當訪問完成的時候使用LeaveCriticalSelection(CRITICAL_SELECTION);
#include <iostream>
#include<Windows.h>
using namespace std;
bool g_bContinue = true;
int g_count1 = 0;
int g_count2 = 0;
DWORD WINAPI ThreadProc(LPVOID lpParam){
for (int i = 0; i < 20; i++)
{
EnterCriticalSection(&g_cs);
g_count1++;
g_count2++;
LeaveCriticalSection(&g_cs);
}
return 0;
}
int main(){
HANDLE g_hThr[2];
InitializeCriticalSection(&g_cs);
g_hThr[0] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
g_hThr[1] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
WaitForSingleObject( g_hThr[0], INFINITE);
WaitForSingleObject( g_hThr[1], INFINITE);
g_bContinue = false;
CloseHandle(g_hThr[0]);
CloseHandle(g_hThr[1]);
DeleteCriticalSection(&g_cs);
Sleep(1000);
cout << "g_count1 = " << g_count1 << "\t g_count2 = " << g_count2 << endl;
}
追夢的飛飛
於廣州中山大學 20131022
HomePage: http://yangtengfei.duapp.com