各位看官們,大家好,上一回中咱們說的是線程同步之信號量的例子,這一回咱們繼續說該例子。閒話休提,言歸正轉。讓我們一起talk C栗子吧!
我們在上一回中詳細介紹了互斥量相關函數的用法,這一回中,我們介紹如何使用這些函數來操作互斥量。
下面是詳細的操作步驟:
1.定義一個互斥量A,用來同步線程; 2.在創建線程的進程中使用pthread_mutex_init函數初始化互斥量,互斥量的屬性使用默認值; 3.在讀取數據的線程中讀取數據,首先使用pthread_mutex_lock函數對互斥量A進行加鎖操作;然後讀取數據,最後使用pthread_mutex_unlock函數對互斥量A進行解鎖操作; 4.在第寫數據的線程中修改數據,首先使用pthread_mutex_lock函數對互斥量A進行加鎖操作;然後修改數據,最後使用pthread_mutex_unlock函數對互斥量A進行解鎖操作; 5.在創建線程的進程中使用pthread_mutex_destroy函數釋放互斥量相關的資源;看官們,正文中就不寫代碼了,詳細的代碼放到了我的資源中,大家可以下載使用。
我們寫的代碼是在信號量互斥代碼的基礎上修改而來的,不過我們在代碼中使用互斥量代替了信號量。代碼中了讀/寫數據的函數是自己實現的,目的是為了方便說明問題,在這兩個函數中都使用了延時操作,目的是為了說明讀或者寫數據需要一定的時間。
在程序運行時可能會存在這樣的情況:
讀操作還沒有完成,就開始寫操作,這樣會造成讀操作讀取的數據不准確; 寫操作還沒有完成,就開始讀操作,這樣會造成讀操作讀取的數據不准確;下面是沒有使用互斥量時程序的運行結果,請大家參考:
Create first thread //創建第一個線程
Create second thread //創建第二個線程
Thread ID::3076062016 -----------S----------
[Thread_1] start reading data //第一個線程開始讀取數據(對數據的第一個操作是讀操作)
Thread ID::3067669312 -----------S----------
[Thread_2] start writing data //第二個線程開始修改數據
[Thread_1] data = 0 //第一個線程讀取到的是共享數據的初始值
[Thread_1] end reading data
[Thread_2] data = 1 //第二個線程對共享數據進行修改
[Thread_2] end writing data
[Thread_2] start writing data
[Thread_1] start reading data
[Thread_2] data = 2
[Thread_2] end writing data
[Thread_1] data = 2
[Thread_1] end reading data
[Thread_2] start writing data
[Thread_2] data = 3
[Thread_2] end writing data
[Thread_1] start reading data
[Thread_2] start writing data
[Thread_1] data = 3
[Thread_1] end reading data
[Thread_2] data = 4
[Thread_2] end writing data
Thread ID::3067669312 -----------E---------- //第二個線程結束
[Thread_1] start reading data
[Thread_1] data = 4
[Thread_1] end reading data
Thread ID::3076062016 -----------E---------- //第一個線程結束
從上面的結果中大家可以看到,第二個線程還沒有寫完數據,第一個線程就開始讀取數據,而且讀取到的是共享數據的初始化值。可見他讀取到的值不是第二個線程修改後的數據,或者說不是准確的數據。再往下看,讀取數據的線程和修改數據的線程交替運行,因此線程運行順序也不正確。由此可見,如果不對線程進行同步操作,那麼對共享數據進行操作會生成錯誤的結果。
下面是使用互斥量同步線程後程序的運行結果,請大家參考:
Create first thread //創建第一個線程
Create second thread //創建第二個線程
Thread ID::3075980096 -----------S----------
[Thread_1] start reading data //第一個線程開始讀取數據(對數據的第一個操作是讀操作)
Thread ID::3067587392 -----------S----------
[Thread_1] data = 0 //第一個線程讀取到的是共享數據的初始值
[Thread_1] end reading data //第一個線程讀取共享數據結束
[Thread_2] start writing data //第二個線程開始修改共享數據的值
[Thread_2] data = 1 //第二個線程修改了共享數據的值
[Thread_2] end writing data //第二個線程修改共享數據結束
[Thread_1] start reading data //第一個線程開始讀取共享數據的值
[Thread_1] data = 1 //第一個線程讀取到了正確的共享數據的值
[Thread_1] end reading data //第一個線程讀取共享數據結束
[Thread_2] start writing data
[Thread_2] data = 2
[Thread_2] end writing data
[Thread_1] start reading data
[Thread_1] data = 2
[Thread_1] end reading data
[Thread_2] start writing data
[Thread_2] data = 3
[Thread_2] end writing data
[Thread_1] start reading data
[Thread_1] data = 3
[Thread_1] end reading data
[Thread_2] start writing data
[Thread_2] data = 4
[Thread_2] end writing data
Thread ID::3075980096 -----------E---------- //第一個線程結束
Thread ID::3067587392 -----------E---------- //第二個線程結束
從上面的結果中可以看到,第一個線程首先開始讀取數據,讀取完數據後第二個線程才開始修改數據;此時,第一個線程處於等待狀態,直到第二個線程修改完數據後才開始讀取數據,它讀取到了准確的共享數據。再往下看,讀取數據的線程和修改數據的線程依次有序地運行。由此可見,對線程進行同步操作後,對共享數據進行的操作順序是正確的,從共享數據中讀取到的值也是正確的。另外,再對比一下使用信號量對線程的同步操作。對共享數據的第一次操作是寫操作,而使用互斥量同步線程時,對共享數據的第一次操作是讀操作。正常來講,肯定是先對數據進行修改,然後才能讀數據中的內容。由此可見信號量對線程的運行順序更加嚴格一些。
依據我們的經驗來看,信號量經常用在計數或者對順序有嚴格要求的情況中,而互斥量經常用訪問共享資源的情況中。當然了,在同步線程的時候,大家可以依據自己的需要和程序的要求來選擇信號量和互斥量。
各位看官,關於線程同步之互斥量的例子咱們就說到這裡。欲知後面還有什麼例子,且聽下回分解 。