日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
走進(jìn)Windows線程同步API

WIN32 API雖然提供了CreateThead和ExitThread方法,但是在C++中,永遠(yuǎn)不應(yīng)該使用這兩個(gè)方法創(chuàng)建或結(jié)束線程。而應(yīng)該使用VC++提供的_beginthread、_beginthreadex方法,相應(yīng)的結(jié)束線程方法_endthread、_endthreadex。后者除了在內(nèi)部調(diào)用CreateThread或ExitThread方法外,還負(fù)責(zé)CRT的初始化或銷(xiāo)毀。雖然有直接結(jié)束線程的方法,但在C++最好通過(guò)線程方法正常返回來(lái)結(jié)束線程。直接結(jié)束線程時(shí)C++對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用。

創(chuàng)新互聯(lián)建站專(zhuān)業(yè)為企業(yè)提供前郭網(wǎng)站建設(shè)、前郭做網(wǎng)站、前郭網(wǎng)站設(shè)計(jì)、前郭網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、前郭企業(yè)網(wǎng)站模板建站服務(wù),十多年前郭做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

#include "stdafx.h"

using namespace std;

class Obj

{

public:

Obj() { cout <<"Obj() called" <

~Obj() { cout <<"~Obj() called" <

};

unsigned int WINAPI ThreadFunc(void* pvParam){

cout <(pvParam) <

Obj obj;

_endthreadex(2);

return 1;

}

int _tmain(int argc, _TCHAR* argv[])

{

unsigned int threadId;

char *param = "param";

HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, param, 0, &threadId);

Sleep(100);

DWORD exitCode;

GetExitCodeThread(thread, &exitCode);

cout <<"ExitCode:" <

system("pause");

return 0;

}

這段代碼的輸出為:

param

Obj() called

ExitCode:2

請(qǐng)按任意鍵繼續(xù). . .

_beginthreadex的第一個(gè)參數(shù)為SECURITY_ATTRIBUTES結(jié)構(gòu)指針,可以指定NULL使用默認(rèn)的安全配置。第二參數(shù)為cbStackSize,線程棧大??;設(shè)置為0使用默認(rèn)值,可以通過(guò)鏈接參數(shù)/STACK:[reserve][,commit]控制。第三個(gè)參數(shù)為線程入口方法地址,方法簽名如ThreadFunc所示。第四個(gè)三處為傳遞給入口方法的參數(shù)(值傳遞),具體意義由程序自己解釋。最后一個(gè)參數(shù)是返回的線程ID。返回值為新創(chuàng)建線程的句柄。__endthreadex方法唯一的參數(shù)指定線程的ExitCode。可以通過(guò)GetExitCodeThread方法獲得線程退出碼。

InterLocked系列原子方法

InterLocked系列方法可視為原子的。完成其功能時(shí),保證其他線程不會(huì)訪問(wèn)同一個(gè)資源。例如最簡(jiǎn)單的InterLockedIncrement方法原子自增一個(gè)共享變量。

long g_sum(0);

unsigned int WINAPI ThreadFunc(void* pvParam){

for(int i = 0; i <100000; ++i)

{

InterlockedIncrement(&g_sum);

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

unsigned int threadId;

HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &threadId);

HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &threadId);

Sleep(1000);

cout <<"Sum:" <

system("pause");

return 0;

}

其他方法包括:

InterlockedIncrement64:自增一個(gè)64位整數(shù)。

InterlockedExchangeAdd、InterlockedExchangeAdd64:加和兩個(gè)數(shù)并賦值給第一個(gè)值。

InterlockedCompareExchange:比較并交換一個(gè)數(shù)。

還有很多InterLocked方法,具體參考MSDN文檔。

CriticalSection

通過(guò)EnterCriticalSection和LeaveCriticalSection方法,可以控制同步一段代碼的訪問(wèn)。使用前需要使用InitializeCriticalSection初始化CRITICAL_SECTION。使用方法也很簡(jiǎn)單。

CRITICAL_SECTION g_cs;

long g_sum(0);

unsigned int WINAPI ThreadFunc(void* pvParam){

for(int i = 0; i <100000; ++i)

{

EnterCriticalSection(&g_cs);

g_sum += 2;

LeaveCriticalSection(&g_cs);

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

InitializeCriticalSection(&g_cs);

unsigned int threadId;

HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &threadId);

HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &threadId);

Sleep(1000);

cout <<"Sum:" <

DeleteCriticalSection(&g_cs);

system("pause");

return 0;

}

這里有一個(gè)問(wèn)題是,如果同步的代碼塊不是簡(jiǎn)單g_sum += 2,而是可能拋出異常的復(fù)雜代碼。就需要確保LeaveCriticalSection一定被調(diào)用。不再使用后使用DeleteCriticalSection方法刪除之。

class CSManager

{

public:

CSManager(CRITICAL_SECTION *cs) : m_cs(cs)

{

EnterCriticalSection(m_cs);

}

~CSManager()

{

LeaveCriticalSection(m_cs);

}

private:

CRITICAL_SECTION *m_cs;

};

//...

for(int i = 0; i <100000; ++i)

{

CSManager CSMgr(&g_cs);

g_sum += 2;

}

//...

CSManager在構(gòu)造函數(shù)中調(diào)用EnterCriticalSection,析構(gòu)函數(shù)中調(diào)用LeaveCriticalSection。保證在代碼塊結(jié)束時(shí)調(diào)用Leave方法。

另外除了使用阻塞的Enter方法,還有一個(gè)TryEnterCriticalSection,該方法嘗試進(jìn)去CriticalSetion,如果失敗,不會(huì)阻塞,而是立即返回FALSE。

SRWLOCK

SRWLOCK具有和CriticalSection類(lèi)似的功能。另外還具有讀寫(xiě)鎖分離的分離的功能??梢允褂肁cquireSRWLockShared獲取共享的讀鎖。使用AcquireSRWLockExclusive獲取獨(dú)占的寫(xiě)鎖。使用對(duì)應(yīng)的ReleaseSRWLockShared/Exclusive方法施放鎖。同樣地,使用前需要使用InitializeSRWLock初始化。

SRWLOCK g_lock;

long g_sum(0);

unsigned int WINAPI ReadThreadFunc(void* pvParam){

for(int i = 0; i <10; ++i)

{

AcquireSRWLockShared(&g_lock);

cout <

ReleaseSRWLockShared(&g_lock);

Sleep(1);

}

return 0;

}

unsigned int WINAPI WriteThreadFunc(void* pvParam){

for(int i = 0; i <100000; ++i)

{

AcquireSRWLockExclusive(&g_lock);

g_sum += 2;

ReleaseSRWLockExclusive(&g_lock);

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

InitializeSRWLock(&g_lock);

unsigned int threadId;

HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, ReadThreadFunc, NULL, 0, &threadId);

HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, ReadThreadFunc, NULL, 0, &threadId);

HANDLE thread3 = (HANDLE)_beginthreadex(NULL, 0, WriteThreadFunc, NULL, 0, &threadId);

Sleep(1000);

cout <<"Sum:" <

system("pause");

return 0;

}

SRWLOCK不具備類(lèi)似于TryEnterCriticalSection的非阻塞方法。大多數(shù)情況下,SRWLOCK比CRITICAL_SECTION有更好的性能。

Condition Variable

為實(shí)現(xiàn)近點(diǎn)的生產(chǎn)者消費(fèi)者問(wèn)題。我們可以使用兩個(gè)CONDITION_VARIABLE:g_full,g_empty來(lái)實(shí)現(xiàn)。在緩沖區(qū)滿(mǎn)的時(shí)候,生產(chǎn)者線程調(diào)用SleepConditionVariableSRW(&g_full, &g_lock, INFINITE, 0)施放獲得的鎖并等待g_full。緩沖區(qū)空的時(shí)候,消費(fèi)者可以調(diào)用leepConditionVariableSRW(&g_empty, &g_lock, INFINITE, 0)施放獲得的鎖并等待g_empty。掉進(jìn)滿(mǎn)足后,可是使用WakeAllConditionVariable喚醒所有等待的線程或者使用WakeConditionVariable喚醒一個(gè)等待的線程。

和Condition Variable配置使用的可以使CrticalSection也可以使SRWLock。

BOOL SleepConditionVariableCS(

PCONDITION_VARIABLE pConditionVariable,

PCRITICAL_SECTION pCriticalSection,

DWORD dwMilliseconds);

BOOL SleepConditionVariableSRW(

PCONDITION_VARIABLE pConditionVariable,

PSRWLOCK pSRWLock,

DWORD dwMilliseconds,

ULONG Flags);

參數(shù)dwMilliseconds指定等待超時(shí)的時(shí)間,如果超時(shí)方法返回FASLE;INFINITE指定等待不超時(shí)。參數(shù)Flags指定被喚醒時(shí)嘗試獲得的鎖的類(lèi)型。CONDITION_VARIABLE_LOCKMODE_ SHARED指定獲得共享鎖或者0指定獲得獨(dú)占鎖。

const int MAX_SIZE = 10;

CONDITION_VARIABLE g_full;

CONDITION_VARIABLE g_empty;

SRWLOCK g_lock;

list products;

unsigned int WINAPI ProduceThreadFunc(void* pvParam)

{

int i(0);

while(true)

{

Sleep(rand() % 100);

AcquireSRWLockExclusive(&g_lock);

if (products.size() >= MAX_SIZE)

{

SleepConditionVariableSRW(&g_full, &g_lock, INFINITE, 0);

}

else

{

cout <<"Produce Product:" <

products.push_back(Product(i++));

}

WakeAllConditionVariable(&g_empty);

ReleaseSRWLockExclusive(&g_lock);

}

return 0;

}

unsigned int WINAPI ConsumeThreadFunc(void* pvParam)

{

while(true)

{

Sleep(rand() % 100);

AcquireSRWLockExclusive(&g_lock);

if(products.size() == 0)

{

SleepConditionVariableSRW(&g_empty, &g_lock, INFINITE, 0);

}

else

{

Product p = products.front();

products.pop_front();

cout <<"Consume Product:" <

}

WakeAllConditionVariable(&g_full);

ReleaseSRWLockExclusive(&g_lock);

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

srand((unsigned)time(NULL));

InitializeSRWLock(&g_lock);

unsigned int threadId;

HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, ProduceThreadFunc, NULL, 0, &threadId);

HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, ConsumeThreadFunc, NULL, 0, &threadId);

HANDLE thread3 = (HANDLE)_beginthreadex(NULL, 0, ConsumeThreadFunc, NULL, 0, &threadId);

WaitForSingleObject(thread1, INFINITE);

WaitForSingleObject(thread2, INFINITE);

WaitForSingleObject(thread3, INFINITE);

system("pause");

return 0;

}

內(nèi)核態(tài)線程同步方法

除了上面介紹的用戶(hù)態(tài)的線程同步方法。本文繼續(xù)通過(guò)幾個(gè)簡(jiǎn)單例子演示內(nèi)核態(tài)的線程同步方法的使用。內(nèi)核態(tài)線程同步方法在性能上肯定比用戶(hù)態(tài)同步方法要差很多。但可以在多個(gè)進(jìn)程間共享。

創(chuàng)建所有的內(nèi)核態(tài)同步對(duì)象都范圍一個(gè)內(nèi)核對(duì)象句柄HANDLE。通過(guò)WaitForSingleObject或者WaitForMultipleObjects等待內(nèi)核同步對(duì)象轉(zhuǎn)換為已傳信狀態(tài)(signaled)。如果等待的是線程或者進(jìn)程對(duì)象,那么對(duì)應(yīng)線程或進(jìn)程結(jié)束后即轉(zhuǎn)換為已傳信狀態(tài)。同時(shí)還可以指定一個(gè)超時(shí)時(shí)間。WaitForSingleObject包括WAIT_OBJECT_0,WAIT_TIMEOUT和WAIT_FAILED。不再使用后調(diào)用CloseHandle釋放引用。

DWORD dw = WaitForSingleObject(hProcess, 5000);

switch (dw) {

case WAIT_OBJECT_0:

// The process terminated.

break;

case WAIT_TIMEOUT:

// The process did not terminate within 5000 milliseconds.

break;

case WAIT_FAILED:

// Bad call to function (invalid handle?)

break;

}

WaitForMultipleObjects如果指定參數(shù)bWaitAll為T(mén)RUE,則等待所有對(duì)象都轉(zhuǎn)換為已傳信狀態(tài)后才返回,如果為指定bWaitAll為FALSE,則任意對(duì)象轉(zhuǎn)換為已傳信狀態(tài)即返回??梢酝ㄟ^(guò)以下方法來(lái)判斷是那個(gè)內(nèi)核同步對(duì)象。

h[0] = hProcess1;

h[1] = hProcess2;

h[2] = hProcess3;

DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000);

switch (dw) {

case WAIT_FAILED:

// Bad call to function (invalid handle?)

break;

case WAIT_TIMEOUT:

// None of the objects became signaled within 5000 milliseconds.

break;

case WAIT_OBJECT_0 + 0:

// The process identified by h[0] (hProcess1) terminated.

break;

case WAIT_OBJECT_0 + 1:

// The process identified by h[1] (hProcess2) terminated.

break;

case WAIT_OBJECT_0 + 2:

// The process identified by h[2] (hProcess3) terminated.

break;

}

Event

Event語(yǔ)義上可以理解為一個(gè)事件是否發(fā)生。SetEvent方法設(shè)置Event為Signaled狀態(tài)。Event有兩種類(lèi)型。第一種是自動(dòng)重置的事件,調(diào)用SetEvent方法后,喚醒一個(gè)等待的線程后即自動(dòng)轉(zhuǎn)換為未傳信狀態(tài)。第二種是手動(dòng)重置事件,調(diào)用SetEvent方法后,需要調(diào)用ResetEvent方法設(shè)置事件為未傳信狀態(tài)。PulseEvent相當(dāng)于調(diào)用SetEvent后立即調(diào)用ResetEvent。對(duì)于手動(dòng)重置時(shí)間,PulseEvent會(huì)喚醒所有等待的線程。而對(duì)于自動(dòng)重置的事件PulseEvent只會(huì)喚醒一個(gè)等待的線程。

HANDLE g_taskEvent;

unsigned int WINAPI ComputationTask(void* pvParam)

{

WaitForSingleObject(g_taskEvent, INFINITE);

for(int i = 0; i <10; ++i)

{

cout <<"comput " <

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

g_taskEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

unsigned int threadId;

HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, ComputationTask, NULL, 0, &threadId);

system("pause");

SetEvent(g_taskEvent);

ResetEvent(g_taskEvent);

WaitForSingleObject(thread1, INFINITE);

system("pause");

return 0;

}

上面是一個(gè)簡(jiǎn)單的例子,ComputationTask線程等待用戶(hù)輸入后才開(kāi)始計(jì)算任務(wù)。

Semaphore

Semaphore維護(hù)一個(gè)資源計(jì)數(shù)count和一個(gè)最大計(jì)數(shù)maxCount。

當(dāng)count大于0時(shí),semaphore處于已傳信狀態(tài)。

當(dāng)count等于0是,semaphore處于未傳信狀態(tài)。

通過(guò)ReleaseSemaphore增加count計(jì)數(shù),WaitForSingleObject減少cout計(jì)數(shù)。count不會(huì)小于0,也不能大于maxCount。

例如,可以使用semaphore控制能夠同時(shí)處理的最大任務(wù)線程數(shù)。當(dāng)有超過(guò)最大數(shù)的更多任務(wù)線程開(kāi)啟時(shí)只能等待其他任務(wù)完成并調(diào)用ReleaseSemaphore方法施放資源引用計(jì)數(shù)。

HANDLE g_semaphore;

unsigned int WINAPI RequstProcesor(void* pvParam)

{

WaitForSingleObject(g_semaphore, INFINITE);

cout <<"Start process request " <

Sleep(1000);

ReleaseSemaphore(g_semaphore, 1, NULL);

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

g_semaphore = CreateSemaphore(NULL, 2, 2, NULL);

HANDLE threads[10];

for(int i = 0; i <10; i++)

{

threads[i] = (HANDLE)_beginthreadex(NULL, 0, RequstProcesor, NULL, 0, NULL);

}

WaitForMultipleObjects(10, threads, TRUE, INFINITE);

system("pause");

return 0;

}

上面的代碼,啟動(dòng)了10個(gè)線程,但只能有2個(gè)現(xiàn)場(chǎng)可以同時(shí)執(zhí)行,更多的線程只能等待。

Mutex

mutex的功能和CriticalSection功能很相似。都是控制一段臨界代碼的互斥訪問(wèn)。通過(guò)WaitForSingleObject等待mutex。ReleaseMutex釋放mutex。

mutex維護(hù)一個(gè)threadId和一個(gè)使用計(jì)數(shù)count。如果CreateMutex的參數(shù)bInitialOwner為T(mén)RUE,這threadId為調(diào)用線程,cout為1。否則都初始為0。

如果threadId為0,mutex沒(méi)有被任何線程使用,處于已傳信狀態(tài)。如果threadId不為0,mutex處于未傳信狀態(tài)。mutex和其他內(nèi)核同步對(duì)象一個(gè)不同的特殊地方在于。即時(shí)mutex處于未傳信狀態(tài)。如果調(diào)用WaitForSingleObject的線程是mutex的threadId對(duì)應(yīng)的線程,WaitForSingleObject不會(huì)阻塞相當(dāng)于處于已傳信狀態(tài)。下面的例子演示了mutex的使用。

HANDLE g_mutex;

void ProcessA()

{

WaitForSingleObject(g_mutex, INFINITE);

cout <<"ProcessA" <<" by thread " <

ReleaseMutex(g_mutex);

}

void ProcessB()

{

WaitForSingleObject(g_mutex, INFINITE);

ProcessA();

cout <<"ProcessB" <<" by thread " <

ReleaseMutex(g_mutex);

}

unsigned int WINAPI ThreadFunc(void* pvParam)

{

ProcessB();

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

g_mutex = CreateMutex(NULL, FALSE, NULL);

HANDLE threads[10];

for(int i = 0; i <10; i++)

{

threads[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, NULL);

}

WaitForMultipleObjects(10, threads, TRUE, INFINITE);

system("pause");

return 0;

}


網(wǎng)站名稱(chēng):走進(jìn)Windows線程同步API
文章位置:http://m.5511xx.com/article/ccopdeh.html