系統中全部的線程必須訪問系統資源,好比堆,串口,文件,窗口以及無數其餘資源。若是一個線程獨佔了對某個資源的訪問,那麼其餘線程就沒法完成他們的工做。另外一方面,咱們頁不能讓任何線程在任什麼時候刻都能訪問任何資源。設想有一個線程正在寫入一塊內存,而同時另外一個線程正在從同一塊內存中讀取數據,那麼這個數據將變得亂七八糟,毫無用處。此時就須要線程同步。緩存
線程同步經常使用的方法:併發
1.原子訪問(Interlocked系列函數):函數
必須保證傳給這些函數的變量地址是通過對齊的,不然這些函數可能會失敗。優化
優勢:執行速度極快,不須要在用戶模式和內核模式之間進行切換。ui
缺點:只能對一個數進行操做。spa
LONG InterlockedIncrement(PLONG plAddend);//plAddend增長1
LONG InterlockedDecrement(PLONG plAddend);//減少1
LONG InterlockedExchange(PLONG volatile plTarget,LONG lValue);//32位,用value替換Target,返回以前的值
LONGLONG InterlockedExchange64(PLONG volatile plTarget,LONGLONG lValue);//64位
PVOID InterlockedExchangePointer(PVOID* volatile ppvTarget,PVOID pvValue);//x86下是32位,x64下是64位
LONG InterlockedExchangeAdd(PLONG volatile plAddend,LONG lIncrement);//Addend增長Increment
LONGLONG InterlockedExchangeAdd64(PLONGLONG volatile pllAddend,LONGLONG llIncrement);
PLONG INterlockedCompareExchange(PLONG plDestination,LONG lExchange,LONG lComparand);//函數會將Destination當前值與參數Comparand的值進行比較,若是相等則替換爲Comparand的值,返回初始值
LONG InterlockedCompareExchangePointer(PVOID* ppvDestination,PVOID pvExchange,PVOID pvComparand);
volatile關鍵字:告訴編譯器這個變量可能會被應用程序以外的其餘東西修改,好比操做系統、硬件或者一個併發執行的線程。確切的說,volatile限定符告訴編譯器不要對這個變量進行任何形式的優化,而是始終從變量在內存中的位置讀取變量的值。操作系統
2.關鍵段(Critical Section):是一段代碼,它在執行以前須要獨佔對一些共享資源的訪問權。線程
優勢:容易使用,內部運用Interlocked函數執行速度很快。code
缺點:沒法在多個進程之間對線程進行同步(其實Ring3的同步方式都沒法在多個進程之間不一樣線程同步)blog
使用方法:
CRITICAL_SECTION g_cs;//定義爲全局
//使用以前先初始化
InitializeCriticalSection(&g_cs);
EnterCriticalSection(&g_cs); .......do Some Things..... LeaveCriticalSection(&g_cs);
//使用完清理cs結構
DeleteCriticalSection(&g_cs);
任何須要訪問共享資源的代碼,都必須包含在EnterCriticalSection和LeaveCriticalSection之間。
若是共享資源在使用中,則EnterCriticalSection就會使線程處於等待狀態,可使用下面函數,這個函數會判斷資源是否在使用,若是使用中則直接返回,不會將線程切換到等待狀態。
BOOL TryEnterCriticalSection(PCRITICAL_SECTION pcs);
3.Slim讀/寫鎖:讀寫鎖目的和關鍵段相同,對一個資源進行保護不讓其餘線程訪問它。可是讀寫鎖容許咱們區分那些想要讀取資源的線程和寫入資源的線程。
void InitializeSRWLock(PSRWLOCK SRWLock);//使用以前初始化讀寫鎖 void AcquireSRWLockExclusive(PSRWLOCK SRWLock);//寫入者線程獲取鎖 void ReleaseSRWLockExclusive(PSRWLOCK SRWLock);//寫入者線程釋放鎖 //讀取者線程 void AcquireSRWLockShared(PSRWLOCK SRWLock); void ReleaseSRWLockShared(PSRWLOCK SRWLock); //不須要刪除或者銷燬SRWLOCK的函數,系統會自動執行清理工做
與關鍵段的區別:1.讀寫鎖不存在TryEnter*的函數,若是鎖已經被佔用,那麼獲取鎖就會致使線程等待;
2.不能遞歸得到SRWLOCK,也就是說,一個線程不能爲了屢次寫入資源而屢次鎖定資源,而後在屢次調用ReleaseSRWLock*來釋放對資源的鎖定。
補充知識:
高速緩存行:當CPU從內存中讀取一個字節的時候,它並不僅是從內存中取回一個字節,而是取回一個高速緩存行。高速緩存行可能包含32字節,64字節甚至是128字節(取決於CPU)。在多CPU的機器上當一個CPU修改了高速緩存行的一個字節時,機器中的其餘CPU會受到通知,並使本身的高速緩存行做廢。
加入條件變量的鎖:
BOOL SleepConditionVariableCS( PCONDITION_VARIABLE pConditionVariable, PCRITICAL_SECTION pCriticalSection,
DWORD dwMilliseconds);
BOOL SleepConditionVariableSRW(
PCONDITION_VARIABLE pConditionVariable,
PSRWLOCK pSRWLock,
DWORD dwMilliseconds,
ULONG Flags);
VOID WakeConditionVariable(
PCONDITION_VARIABLE ConditionVariable);
VOID WakeAllConditionVariable(
PCONDITION_VARIABLE ConditionVariable);