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