互斥量原理及簡單案例

2021-08-01 23:00:59 字數 3229 閱讀 6222

同步即協同步調,按預定的先後次序執行。

執行緒同步,指乙個執行緒發出某一功能呼叫時,在沒有得到結果之前,該呼叫不返回。同時其它執行緒為保證資料一致性,不能呼叫該功能。

舉例1: 銀行存款 5000。櫃檯,折:取3000;提款機,卡:取 3000。剩餘:2000

舉例2: 記憶體中100位元組,執行緒t1欲填入全1, 執行緒t2欲填入全0。但如果t1執行了50個位元組失去cpu,t2執行,會將t1寫過的內容覆蓋。當t1再次獲得cpu繼續 從失去cpu的位置向後寫入1,當執行結束,記憶體中的100位元組,既不是全1,也不是全0。

產生的現象叫做「與時間有關的錯誤」(time related)。為了避免這種資料混亂,執行緒需要同步。

「同步」的目的,是為了避免資料混亂,解決與時間有關的錯誤。實際上,不僅執行緒間需要同步,程序間、訊號間等等都需要同步機制。

因此,所有「多個控制流,共同操作乙個共享資源」的情況,都需要同步。

1. 資源共享(獨享資源則不會)	

2. 排程隨機(意味著資料訪問會出現競爭)

3. 執行緒間缺乏必要的同步機制。

以上3點中,前兩點不能改變,欲提高效率,傳遞資料,資源必須共享。只要共享資源,就一定會出現競爭。只要存在競爭關係,資料就很容易出現混亂。

所以只能從第三點著手解決。使多個執行緒在訪問共享資源的時候,出現互斥。

linux中提供一把互斥鎖mutex(也稱之為互斥量)。

每個執行緒在對資源操作前都嘗試先加鎖,成功加鎖才能操作,操作結束解鎖。

資源還是共享的,執行緒間也還是競爭的,

但通過「鎖」就將資源的訪問變成互斥操作,而後與時間有關的錯誤也不會再產生了。

看如下程式:該程式是非常典型的,由於共享、競爭而沒有加任何同步機制,導致產生於時間有關的錯誤,造成資料混亂:

#include #include #include void *tfn(void *arg)

return null;

}int main(void)

pthread_join(tid, null);

return 0;

}

pthread_mutex_init函式

pthread_mutex_destroy函式

pthread_mutex_lock函式

pthread_mutex_trylock函式

pthread_mutex_unlock函式

以上5個函式的返回值都是:成功返回0, 失敗返回錯誤號。

pthread_mutex_t 型別,其本質是乙個結構體。為簡化理解,應用時可忽略其實現細節,簡單當成整數看待。

pthread_mutex_t mutex; 變數mutex只有兩種取值1、0。

pthread_mutex_init函式

初始化乙個互斥鎖(互斥量) ---> 初值可看作1

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

參1:傳出引數,呼叫時應傳 &mutex

restrict關鍵字:只用於限制指標,告訴編譯器,所有修改該指標指向記憶體中內容的操作,只能通過本指標完成。不能通過除本指標以外的其他變數或指標修改

參2:互斥量屬性。是乙個傳入引數,通常傳null,選用預設屬性(執行緒間共享)。 參apue.12.4同步屬性

1. 靜態初始化:如果互斥鎖 mutex 是靜態分配的(定義在全域性,或加了static關鍵字修飾),可以直接使用巨集進行初始化。e.g. pthead_mutex_t muetx = pthread_mutex_initializer;

2. 動態初始化:區域性變數應採用動態初始化。e.g. pthread_mutex_init(&mutex, null)

pthread_mutex_destroy函式

銷毀乙個互斥鎖

int pthread_mutex_destroy(pthread_mutex_t *mutex);

pthread_mutex_lock函式

加鎖。可理解為將mutex--(或-1)

int pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_unlock函式

解鎖。可理解為將mutex ++(或+1)

int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_trylock函式

嘗試加鎖

int pthread_mutex_trylock(pthread_mutex_t *mutex);

加鎖與解鎖

lock與unlock:

lock嘗試加鎖,如果加鎖不成功,執行緒阻塞,阻塞到持有該互斥量的其他執行緒解鎖為止。

unlock主動解鎖函式,同時將阻塞在該鎖上的所有執行緒全部喚醒,至於哪個執行緒先被喚醒,取決於優先順序、排程。預設:先阻塞、先喚醒。

例如:t1 t2 t3 t4 使用一把mutex鎖。t1加鎖成功,其他執行緒均阻塞,直至t1解鎖。t1解鎖後,t2 t3 t4均被喚醒,並自動再次嘗試加鎖。

可假想mutex鎖 init成功初值為1。 lock 功能是將mutex--。 unlock將mutex++

lock與trylock:

lock加鎖失敗會阻塞,等待鎖釋放。

trylock加鎖失敗直接返回錯誤號(如:ebusy),不阻塞。

下面這段**是使用互斥量之後,由於使用了互斥量,保證了主線程或者子執行緒能夠兩次使用printf結束之後才會易主:

#include #include #include pthread_mutex_t mutex = pthread_mutex_initializer;

void *tfn(void *arg)

return null;

}int main(void)

pthread_join(tid, null);

return 0;

}

死鎖

1. 執行緒試圖對同乙個互斥量a加鎖兩次。

2. 執行緒1擁有a鎖,請求獲得b鎖;執行緒2擁有b鎖,請求獲得a鎖

簡單工廠與工廠模式原理及案例分析

工廠方法的規範性定義描述為 工廠方法模式定義了乙個建立物件的介面,但由子類決定要例項化的類是哪乙個。工廠方法讓類把例項化推遲到子類。在學習工廠方法前,我們應該先了解簡單工廠這一種偽模式。之所以稱之為偽模式,是因為嚴格意義上講這並不算是一種模式,個人感覺更像是將某一功能抽象成了乙個功能函式。程式設計的...

互斥量概念,用法,死鎖演示及解決詳解

保護共享資料,用 把共享資料鎖住,其他想操作共享資料的執行緒得等待解鎖。互斥量的概念 互斥量是個類物件。多個執行緒嘗試lock鎖上。結果 只有乙個執行緒能夠鎖定成功,成功的標誌是lock函式返回。如果沒鎖成功,那麼流程就會卡在lock這,不斷嘗試去鎖,一直到成功。互斥量使用起來要小心,保護資料不要多...

11 K Means 原理及案例

unsupervised learning 非監督學習 只有特徵值,沒有目標值 聚類 主要方法 k means k 需要分成的類別數 隨機設定k個特徵空間內的點作為初始的聚類中心 紅,綠,藍 k 3 給定 對於其他每個點計算到k個中心的距離,未知的點選擇最近的乙個聚類 中心點作為標記類別,形成3個族...