<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在多線程環境下,線程同步是不可避免的話題。Windows環境下的線程同步分為:用戶態同步 與 內核態同步。 下面我們先了解用戶態同步的一些方法。 - 使用Interlocked系列函數。簡單易用的函數。 - 關鍵段。用來對關鍵資源實現獨享訪問。 - Slim讀寫鎖。靈活的進行寫獨享讀共享操作。 - 條件變量。當線程要進行較為復雜的條件進行同步時,可以實現。 Interlocked系列函數。 Windows提供了Interlocked系列函數,用來原子的對數據進行增減或交換。如自旋轉鎖,就可以通過InterlockedExchange函數實現。 ~~~ BOOL g_fResourceInUse = FALSE; void Func1() { // InterlockedExchange會一直原子設置g_fResourceInUse為TRUE,同時返回g_fResourceInUse // 上一次的值。當g_fResourceInUse為初始值FALSE或被另一線程設置為FALSE后,該循環才會結束。 // 以此自循環(自旋鎖)方式來實現對資源的獨占訪問。 while (InterlockedExchange(&g_fResourceInUse,TRUE) == TRUE) Sleep(0); // Access the resource, do something ... // Do not need the resource anymore, release it InterlockedExchange(&g_fResourceInUse,FALSE) } ~~~ 注意,這種循環方式會占用CPU大量時間,不建議在單CPU機器上運行。(可以用關鍵段代替或用C++11標準中的atom系列函數代替) 關鍵段 上面使用自旋鎖的方式進行同步顯然是低效的。因為等待線程依然處于可調度狀態,仍然會占用CPU時間。Windows提供了一系列函數,讓線程同步。這一系列函數保證了在線程獲得想要的資源之前,不被CPU調度,直到其要求的資源可被線程訪問為止。關鍵段就是其一,其實關鍵段的實現是通過事件內核對象的。 運用關鍵段五個步驟: 1、聲明一個可以被多個線程訪問到其地址的關鍵段變量。 2、在使用關鍵段前,調用InitializeCriticalSection函數初始化關鍵段。 2、在進入資源前調用EnterCriticalSection,請求進入關鍵段(若進入不了,則線程等待) 3、在離開資源時,調用LeaveCriticalSection,離開關鍵段。 若確定了關鍵段已經不被任何線程再使用,則要銷毀關鍵段對象。 4、在不再使用關鍵段時,調用DeleteCriticalSection銷毀關鍵段。 ~~~ CRITICAL_SECTION g_cs; int g_sum = 0; //初始化關鍵段,注意不要多次初始化,否則后果是未定義的 <pre name="code" class="cpp">InitializeCriticalSection(&g_cs); ~~~ ~~~ void ThreadFunc1() { ?? ?? EnterCriticalSection(&g_cs); ?? g_sum++; ?? LeaveCriticalSection(&g_cs); } void ThreadFunc2() { ?? ?? EnterCriticalSection(&g_cs); ?? g_sum++; ?? LeaveCriticalSection(&g_cs); } ... ... // 不再使用critical section,顯示銷毀 DeleteCriticalSection(&g_cs); ~~~ 關鍵段最容易忘記 ~~~ LeaveCriticalSection ~~~ ,這時候可以用RAII技巧來進行簡單的封裝。 關于關鍵段的細節 1、若一個線程已經成功進入關鍵段,則可以多次調用EnterCriticalSection,相應的,要調用多次LeaveCriticalSection來離開臨界區。 2、對于跨進程的線程同步,可以使用mutex對象。 可以使用TryEnterCriticalSection進入關鍵段,他不會使線程進入等待,而是返回布爾值表示是否獲得了關鍵段。對于返回TRUE,需要調用LeaveCriticalSection。 關鍵段與旋轉鎖 當線程由于得不到關鍵段而進入等待狀態時,會進行用戶態和內核態切換,這會占用大量的CPU時間。在多處理器的環境下,可能的一種情況是,用戶/內核態的切換還未結束,占用關鍵段的線程可能已經釋放了關鍵段。 在多處理器的情況下,可以使用 [**InitializeCriticalSectionAndSpinCount**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683476%28v=vs.85%29.aspx) 函數來初始化關鍵段。其函數原型如下 ~~~ BOOL WINAPI InitializeCriticalSectionAndSpinCount( _Out_ LPCRITICAL_SECTION lpCriticalSection, _In_ DWORD dwSpinCount ); ~~~ 其中參數dwSpinCout用來設置旋轉鎖循環次數。[**SetCriticalSectionSpinCount**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686197%28v=vs.85%29.aspx) 可以重設自旋轉鎖次數。 該函數會在進入內核態前,旋轉設置的循環次數來獲取關鍵段。若在旋轉鎖階段獲取關鍵段,則不會進入內核態。 注意,在單CPU模式下,dwSpinCout是被忽略的,總是為0。因為在單CPU下, ~~~ InitializeCriticalSectionAndSpinCount ~~~ 是沒有意義的:CPU在旋轉鎖階段被線程占用,其他線程根本沒有時機來釋放關鍵段。但我們仍可以這樣初始化關鍵段,以應對未來可能的多CPU環境。 Slim讀寫鎖 一般的,對于線程的同步,讀是可以共享的,而寫則是互斥的。因此Windows提供了讀寫鎖機制。 與關鍵段類似,在使用讀寫鎖之前,要調用[**InitializeSRWLock**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683483%28v=vs.85%29.aspx)函數初始化讀寫鎖。 利用讀寫鎖要分清讀者和寫者。 讀寫鎖使用步驟 1、聲明SRWLOCK對象。 2、用InitializeSRWLock函數初始化SRWLOCK對象。 3.1、對于讀者,調用 [**AcquireSRWLockShared**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms681934%28v=vs.85%29.aspx) [**ReleaseSRWLockShared**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms685080%28v=vs.85%29.aspx) 以共享的方式獲取,釋放的讀寫鎖。若該鎖沒被占用或被其他線程讀,則立即獲得鎖,否則等待。 3.2、對于寫者,調用 [**AcquireSRWLockExclusive**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms681930%28v=vs.85%29.aspx) [**ReleaseSRWLockExclusive**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms685076%28v=vs.85%29.aspx) 以獨占的方式獲取,釋放的讀寫鎖。若該鎖未被占用,則立即獲得鎖,否則等待。 Slim與關鍵段的對比 Slim鎖與關鍵段主要有以下兩點區別 1、Slim鎖不能夠遞歸獲取,即當一個線程Acquire并獲得Slim鎖之后,不能夠再次Acquire同一把鎖。 2、不存在TryEnter類似函數獲取Slim鎖。 3、Slim鎖不用顯示銷毀,系統會自動釋放。 4、總體上說,Slim鎖的效率優于關鍵段。 多種同步方法的效率對比 ![](https://box.kancloud.cn/82c440c7466c6449356a9b8660ba37f6_617x136.jpg) 條件變量同步 有時候需要線程原子方式釋放獲得的鎖同時阻塞自身,直到某一條件成立為止。這時候可以通過條件變量進行同步。 等待條件變量函數。當條件被滿足,線程被喚醒后,會自動得到鎖。 [**SleepConditionVariableCS**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686301%28v=vs.85%29.aspx) [**SleepConditionVariableSRW**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686304%28v=vs.85%29.aspx) 喚醒等待條件的線程函數 [**WakeAllConditionVariable**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms687076%28v=vs.85%29.aspx) [**WakeConditionVariable**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms687080%28v=vs.85%29.aspx)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看