Windows幾種線程同步方法介紹

來源:互聯網
上載者:User

系統中的所有線程都要訪問系統資源,一個線程霸佔某個資源,其他需要該資源的線程就不能完成自己的任務;另外如一個線程在讀取某塊記憶體中的資料,而另一個線程又正在修改這塊記憶體的值,這同樣不是我們想要的,所以線程之間必須要有一套自己的規則,不然就淩亂了。線程之間需要通訊,如A線程霸佔某個B線程需要的資源X,在A佔用期間,B線程只能等待,或處於掛起狀態,當A線程用完資源X後,系統會告訴線程B,資源X可以用了,或是將處於掛起狀態的線程B喚醒,然後線程B就獲得對資源X的控制權,其他想用資源X的線程就得經曆B剛才的遭遇。當多個線程同時需要某個資源時必須遵守下面兩個規則:

1:多個線程“同時”訪問資源,不能破壞資源的完整性。

2:一個線程需要通知其他線程某項任務已經完成。

原子訪問:Interlocked系列函數。多線程編程大部分情況與原子訪問有關,即一個線程在訪問某個資源時,確保沒有其他線程能訪問該資源。

增量函數InterlockedExchangeAdd結構如下:

InterlockedExchangeAdd(

    unsigned long volatile *Addend,//被增量變數的地址

    unsigned long Value//增量值

)

Volatile表示每次都成記憶體中讀取資料,而不會從快取中讀取資料,如一個全域變數,在一個多線程函數中被修改,在多核CPU中,這個變數可能在多個CPU的快取中都有副本,如果不用volatile修飾,那麼可能會因為最佳化的原因,CPU不會讀記憶體中的資料,而是直接從快取中讀取資料,在這種情況下,很可能這個值已經被修改了,這樣CPU讀取到的不是最新的資料,程式肯定會出錯,用volatile修飾後,這個變數的所有快取就會失效,就不會出現這種問題。在多線程編程中volatile作用非常大,效率也最高。但他就是只能修飾單個變數,不能修飾程式碼片段。

InterlockedExchangeAdd執行的速度是非常快的,只需要佔用幾個CPU周期。用InterlockedExchangeAdd來修改某個變數的值,好像有點大材小用了,因為用Volatile就足夠了,簡單迅速。但在實現旋轉鎖時InterlockedExchange就非常有用。旋轉鎖的代碼大致如下:

        bool sourceIsUse=false;        void fun()        {            //一直等待直到資源可用            while(InterlockedExchange(&sourceIsUse,true)==true)            {                Sleep(0);            }            //訪問資源的操作            ......            //資源用好了,開啟鎖,讓其他等待的資源訪問            InterlockedExchange(&sourceIsUse,false);        }

 

InterlockedExchange:將第一個參數的值修改成第二個參數的值,返回第一個參數原來的值。在第一個線程就來的時候,它順利的闖過了While迴圈,並上了鎖,導致while始終為true,後來的線程就一直在while裡面打轉,當前面的線程用完之後,他就會把鎖開啟,然後新來的線程就可以跳出while迴圈,並上鎖(在等待時一直在上鎖),開鎖獨佔資源了,新來的線程又開始等待。就像大廈前門的旋轉門,一撥人進去之後,後面的人就只能在外面等,等裡面的人出去之後,後面的人也就可以進去了,周而復始。

 

快取行。當CPU從記憶體中讀取一個位元組時,它並不是真的唯讀一個位元組,而是讀取一個快取行,一個快取行可能是32個位元組、64個位元組或是128個位元組,它始終讀取的位元組數是32的整數倍,這樣CPU就不用非常頻繁的讀取記憶體,從而提高程式的效能,當CPU訪問某塊記憶體是它會訪問這塊記憶體旁邊的記憶體的機率是非常大的,於是就一起讀了。更多關於資料對齊的資訊請看我的文章《資料對齊》。

 

進階線程同步。剛剛簡單的說了一下旋轉鎖,現在又來說旋轉鎖的壞,旋轉鎖的問題在於等待的線程一直在執行毫無用處的該死的死迴圈,浪費CPU的時間,這肯定是不能容忍的,雖然曾經一度容忍過它。當一個線程需要某個資源,而這個資源被另一個線程佔用時,如果這個線程等了一會兒還不能獲得這個資源,那麼這個線程就應該被切換到等待狀態,讓系統充當該線程的代理,當該資源可以被使用時,系統就會將該線程喚醒,然後該線程就可以獨佔該資源。而實現這一功能的就是關鍵段。

 

關鍵段。關鍵段是一小段代碼,在執行之前需要獨佔對一些共用資源的訪問,這種方式可以讓多行代碼以原子的方式進行訪問,當有一個線程對訪問這段代碼時其他線程只能等待。使用關鍵段的步驟如下:

CRITICAL_SECTION g_cs;//構造一個CRITICAL_SECTION執行個體

InitializeCriticalSection(&g_cs);//初始化g_cs的成員

EnterCriticalSection(&g_cs);//進入關鍵段

LeaveCriticalSection(&g_cs);//離開關鍵段

DeleteCriticalSection(&g_cs);//清理g_cs

EnterCriticalSection會檢查結構CRITICAL_SECTION的成員變數,這些成員表示是否有線程正在訪問資源,以及哪個線程正在訪問資源,EnterCriticalSection會進行一些測試。如果沒有線程正在訪問資源,EnterCriticalSection會更新變數成員,以表示已經有線程正在訪問資源,並馬上從EnterCriticalSection返回,繼續執行關鍵段中的代碼,如果變數成員表示已經有線程正在訪問資源,那麼EnterCriticalSection會使用一個事件核心對象把線程切換成等待狀態,等待狀態的線程是不會浪費CPU的時間的,系統會記住這個線程想要使用這個資源,一旦當前線程調用LeaveCriticalSection,系統會自動更新CRITICAL_SECTION的成員變數,並將等待的線程切換成可調度狀態。

LeaveCriticalSection會檢查結構CRITICAL_SECTION的成員變數並將計數器減一,如果計數器變為0,LeaveCriticalSection會更新成員變數表示現在沒有線程訪問資源,若有等待的線程,則將等待的線程切換成可調度的狀態。

 

當一個線程進入關鍵段時,若有線程正在訪問關鍵段,那麼系統就會將新的線程切換成等待狀態,這意味著將線程從使用者模式切換成核心模式,這個切換的開銷大約是1000個CPU周期,這個開銷其實是很大的,所以在EnterCriticalSection內部使用旋轉鎖,並不是馬上將線程切換成等待狀態,而是先用旋轉鎖試探一些,看線程是否釋放了對資源的訪問,如果釋放了,新的線程就不用被切換成等待狀態了,就可以直接存取資源了,也就是說花了旋轉鎖輪詢的時間,如果旋轉鎖輪詢了一段時間,線程還是沒有釋放資源,對不起系統就不會讓它繼續輪詢了,因為系統也不知道還要輪詢多久,畢竟輪詢一直都是在消耗CPU的時間,系統會停止輪詢,將新的線程切換成等待狀態,當前一個資源釋放對資源的訪問,系統會將新的線程切換成可調度狀態。

 

Silm讀/寫鎖。SRWLock的目的和關鍵段是一樣的,就是對資源的保護,不讓其他線程訪問。不同的是,它區分線程是讀線程還是寫線程。我們都是知道,一個資源可以同時被多個線程同時讀,就是不能同時讀,或是讀寫。也是是說寫必須是獨佔的方式,而讀可以以共用的方式訪問。

讀寫鎖調用的函數如下,跟關鍵段差不多,我就不廢話了。

RTL_SRWLOCK lock;

InitializeSRWLock(&lock);

AcquireSRWLockExclusive(&lock);//獨佔的方式訪問

ReleaseSRWLockExclusive(&lock);

AcquireSRWLockShared(&lock);//共用的方式訪問

ReleaseSRWLockShared(&lock);

Windows線程基礎

Windows核心對象簡介

作者:陳太漢

部落格:http://www.cnblogs.com/hlxs/

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.