相比多進程模型,,多線程模型最大的優(yōu)勢在于數(shù)據(jù)共享非常方便,同一進程內(nèi)的多個線程可以使用相同的地址值訪問同一塊內(nèi)存數(shù)據(jù),。但是,,當多個線程對同一塊內(nèi)存數(shù)據(jù)執(zhí)行“讀?處理?更新”操作時,會由于線程的交叉執(zhí)行而造成數(shù)據(jù)的錯誤,。 例如以下代碼段,,當 thread_func() 同時在多個線程中執(zhí)行時,更新到 glob_value 中的值就會互相干擾,,產(chǎn)生錯誤結(jié)果,。
解決這類問題的關鍵在于,當一個線程正在執(zhí)行“讀?處理?更新”操作時,,保證其他線程不會中途闖入與其交叉執(zhí)行,。不可被打斷的執(zhí)行序列稱為臨界區(qū),保證多個線程不會交叉執(zhí)行同一臨界區(qū)的技術稱為線程同步,。 1 互斥鎖的使用最常用的線程同步技術是互斥鎖,,Linux 線程庫中的相關函數(shù)有:
這里pthread的p代表POSIX線程 所有線程都有一個線程號,也就是Thread ID,。其類型為pthread_t,。通過調(diào)用pthread_self()函數(shù)可以獲得自身的線程號。 pthread_mutex_lock() 負責在進入臨界區(qū)之前對臨界區(qū)加鎖,; 當某個線程試圖給一個已經(jīng)處在加鎖狀態(tài)的臨界區(qū)再次加鎖時,,該線程就會被臨時掛起,一直等到該臨界區(qū)被解鎖后,,才會被喚醒并繼續(xù)執(zhí)行,。 如果同時有多個線程等待某個臨界區(qū)解鎖,那下次被喚醒的進程取決于內(nèi)核的調(diào)度策略,,并沒有固定的順序,。 靜態(tài)分配的 mutex 變量在使用之前應該被初始化為 PTHREAD_MUTEX_INITIALIZER,而動態(tài)分配的 mutex 需要調(diào)用 pthread_mutex_init() 進行初始化,,且只被某個線程初始化一次,,可以利用 pthread_once() 函數(shù)方便完成。
多個線程在臨界區(qū)上的執(zhí)行是串行的,,開發(fā)者應該盡量減少程序在臨界區(qū)內(nèi)的停留時間,,以提高程序的并行性。因此,,臨界區(qū)不應該包含任何非必須的邏輯,,以及任何可能帶來高延遲的 IO 等操作 2 互斥鎖的保護范圍和使用順序對互斥鎖加鎖的不恰當使用會造成線程的死鎖,比如下面這兩種情況,。
因此,,開發(fā)者需要仔細規(guī)劃互斥鎖保護范圍和使用順序 3 避免死鎖的兩個加鎖函數(shù)為了避免出現(xiàn)死鎖問題,,可以使用另外兩種變體的鎖定函數(shù),如下所示:
前者可以在鎖定失敗后立即返回,后者可以在一段超時時間后返回,, 應用這兩個函數(shù)可以處理這種錯誤情況,,而避免陷入無限的死鎖中。 在 Linux 中,,實現(xiàn)互斥鎖采用的是 Futex(Fast Userspace Mutex)方案,。在該實現(xiàn)中,只有發(fā)生了鎖的爭用才需要陷入到內(nèi)核空間中處理,,否則所有的操作都可以在用戶空間內(nèi)快速完成,。在大多數(shù)情況下,互斥鎖本身的效率很高,,其平均開銷大約相當于幾十次內(nèi)存讀寫和算數(shù)運算所花費的時間,。 來源:http://www./content-4-220351.html |
|