2013-06-03 58 views
11

我用pthread編寫了一個使用生產者 - 消費者模型的多線程程序。Pthread互斥鎖:pthread_mutex_unlock()消耗大量時間

當我使用英特爾VTune分析器來分析我的程序時,我發現生產者和消費者花費大量時間在pthread_mutex_unlock上。我不明白爲什麼會發生這種情況。我認爲線程可能會等待很長時間才能獲得互斥鎖,但釋放互斥鎖應該很快,對吧?

以下快照來自Intel VTune。它顯示了消費者試圖從緩衝區獲取項目的代碼,以及每個代碼行消耗的時間。

我的問題是,爲什麼pthread_mutex_unlock有這樣的開銷? pthread互斥體本身的問題還是與我使用它的方式有關? enter image description here

+0

如果互斥體上存在大量爭用,則解鎖互斥體可能會很慢,因爲部分解鎖工作正在喚醒等待互斥體的任何線程。 – caf

+6

我認爲如果將'pthread_mutex_unlock()'調用移動到'pthread_cond_signal()'的調用上方,將會看到結果會很有趣。沒有要求在發信號通知條件變量時(僅在等待它時)持有互斥體,並且我懷疑發生了什麼事情是信號引起互斥體的爭用,因爲立即釋放的線程會嘗試獲取互斥體,信令線程仍然成立。 –

+2

@MichaelBurr好點!我測試了你的建議,現在這個程序快了大約40%。 –

回答

2

pthread_mutex_unlock()函數將釋放由互斥量引用的互斥對象。但是,釋放互斥體的方式取決於互斥體的類型屬性。如果調用pthread_mutex_unlock()時互斥體引用的互斥體對象上存在線程阻塞,導致互斥體變爲可用,則調度策略應確定哪個線程將獲取互斥體。

如果互斥體類型爲PTHREAD_MUTEX_NORMAL,則不應提供死鎖檢測。試圖重新鎖定互斥鎖會導致死鎖。如果線程試圖解鎖未鎖定的互斥鎖或解鎖的互斥鎖,則會導致未定義的行爲。

如果互斥類型爲PTHREAD_MUTEX_ERRORCHECK,則應提供錯誤檢查。如果線程試圖重新鎖定已鎖定的互斥鎖,則應返回錯誤。如果線程試圖解鎖未鎖定的互斥鎖或已解鎖的互斥鎖,則應返回錯誤。

如果互斥體類型爲PTHREAD_MUTEX_RECURSIVE,那麼互斥體應保持鎖定計數的概念。當線程第一次成功獲取互斥鎖時,鎖定計數應設置爲1。每次線程重新鎖定此互斥鎖時,鎖定計數應遞增1。每次線程解鎖互斥鎖時,鎖定計數應減1。當鎖計數達到零時,互斥量將可供其他線程獲取。如果線程試圖解鎖未鎖定的互斥鎖或已解鎖的互斥鎖,則應返回錯誤。

如果互斥體類型爲PTHREAD_MUTEX_DEFAULT,則嘗試遞歸鎖定互斥體會導致未定義的行爲。如果未被調用線程鎖定,則試圖解鎖互斥鎖會導致未定義的行爲。嘗試解鎖互斥鎖,如果未鎖定,則會導致未定義的行爲。

我通常更喜歡使用PTHREAD_MUTEX_RECURSIVE互斥量,因爲在這種情況下,互斥量在計數達到零時可用,並且調用線程不再在此互斥鎖上有任何鎖定。