❶ 互斥鎖,自旋鎖,原子操作原理和實現
注意:互斥鎖在上鎖的過程中,需要用自旋鎖保證原子操作(包括修改原子量和鎖的相關數據結構)
自旋鎖是採用忙等的狀態獲取鎖,所以會一直佔用cpu資源,但是允許不關閉中斷的情況下,是可以被其他內核執行路徑搶占的(中斷嵌套的塵納情況下,注意嵌套的中斷不能申請同一個鎖,這樣會造成死等)。同時因為線程對cpu一直保持佔用狀態,所以對小資源加鎖效率比較高,不需要做任何的線程切換,一般情況下如果加鎖資源的運行延遲小於線程或者進程切換的時延則推薦使用自旋鎖。如果需要等待耗時操作,則建議胡激放棄cpu,採用信號量或者互斥鎖
上圖指令可以實現加操作的原子性,但是這種匯流排鎖不能濫用,在沒有共享同步問題的時候,這會阻止cpu並行計算的優化,甚至會阻塞cpu對其他內存的訪問,導致褲兄襪效率的下降。所以除此之外我們可以使用緩存鎖來執行復雜的原子操作。
頻繁使用的內存會緩存在處理器的L1、L2和L3高速緩存里,那麼原子操作就可以直接在處理器內部緩存中進行,並不需要聲明匯流排鎖,在Pentium 6和目前的處理器中可以使用「緩存鎖定」的方式來實現復雜的原子性。 所謂「緩存鎖定」是指內存區域如果被緩存在處理器的緩存行中,並且在Lock操作期間被鎖定,那麼當它執行鎖操作回寫到內存時,處理器不在匯流排上聲言LOCK#信號,而是修改內部的內存地址,並允許它的緩存一致性機制來保證操作的原子性,因為緩存一致性機制會阻止同時修改由兩個以上處理器緩存的內存區域數據,當其他處理器回寫已被鎖定的緩存行的數據時,會使緩存行無效,在如圖2-3所示的例子中,當CPU1修改緩存行中的i時使用了緩存鎖定,那麼CPU2就不能同時緩存i的緩存行。
但是有兩種情況下處理器不會使用緩存鎖定。
未完待續。。。。
https://www.cnblogs.com/alinh/p/6905221.html
https://blog.csdn.net/mcgrady_tracy/article/details/34829019
https://leetcode.com/discuss/interview-question/operating-system/125169/Mutex-vs-Semaphore
https://blog.csdn.net/zxx901221/article/details/83033998
https://leetcode.com/discuss/interview-question/operating-system/134290/Implement-your-own-spinlock
❷ 信號量,互斥鎖,讀寫鎖和條件變數的區別
信號量強調的是線程(或進程)間的同步:「信號量用在多線程多任務同步的,一個線程完成了某一個動作就通過信號量告訴別的線程,別的線程再進行某些動作(大家都 在sem_wait的時候,就阻塞在那裡)。當信號量為單值信號量是,也可以完成一個資源的互斥訪問。
有名信號量:可以用於不同進程間或多線程間的互斥與同步
創建打開有名信號量
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
成功返回信號量指針;失敗返回SEM_FAILED,設置errnoname是文件路察旅徑名,但不能寫成/tmp/a.sem這樣的形式,因為在linux下,sem都是在/dev/shm目錄下,可寫成"/mysem"或"mysem",創建出來的文件都 是"/dev/shm/sem.mysem",mode設置為0666,value設置為信號量的初始值.所需信號燈等已存在條件下指定O_CREAT|O_EXCL卻是個錯誤。
關閉信號量,進程終止時,會自動調用它
int sem_close(sem_t *sem);
成功返回0;失敗返回-1,設置errno
刪除信號量,立即刪除信號量名字,當其他進程都關閉它時,銷毀它
int sem_unlink(const char *name);
等待信號量,測試信號量的值,如果其值小於或等於0,那麼就等待(阻塞);一旦其值變為大於0就將它減1,並返回
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
成功返回0;失敗返回-1,設置errno
當信號量的值為0時,sem_trywait立即返回,設置errno為EAGAIN。如果被某個信號中斷,sem_wait會過早地返回,設置errno為EINTR
發出信號量,給它的值加1,然後喚醒正在等待該信號量的進程或線程
int sem_post(sem_t *sem);
成功返回0;失敗返回-1,不會改變它的值,設滑埋置errno,該函數是非同步信號安全的,可以在信號處理程序里調用它無名信號量,用於進程體內各線程間的互斥和同步,使用如下API(無名信號量,基於內存的信號量)
(1)、sem_init
功能:用於創建一個信號量,並初始化信號量的值。
頭文件:
函數原型: int sem_init (sem_t* sem, int pshared, unsigned int value);
函數傳敗讓凳入值: sem:信號量。pshared:決定信號量能否在幾個進程間共享。由於目前LINUX還沒有實現進程間共享信息量,所以這個值只能取0。
(2)其他函數。
int sem_wait (sem_t* sem);
int sem_trywait (sem_t* sem);
int sem_post (sem_t* sem);
int sem_getvalue (sem_t* sem);
int sem_destroy (sem_t* sem);
功能:sem_wait和sem_trywait相當於P操作,它們都能將信號量的值減一,兩者的區別在於若信號量的值小於零時,sem_wait將會阻塞進程,而sem_trywait則會立即返回。sem_post相當於V操作,它將信號量的值加一,同時發出喚醒的信號給等待的進程(或線程)。
sem_getvalue 得到信號量的值。
sem_destroy 摧毀信號量。
如果某個基於內存的信號燈是在不同進程間同步的,該信號燈必須存放在共享內存區中,這要只要該共享內存區存在,該信號燈就存在。
互斥鎖(又名互斥量)強調的是資源的訪問互斥:互斥鎖是用在多線程多任務互斥的,一個線程佔用了某一個資源,那麼別的線程就無法訪問,直到這個線程unlock,其他的線程才開始可以利用這個資源。比如對全局變數的訪問,有時要加鎖,操作完了,在解鎖。有的時候鎖和信號量會同時使用的」
也就是說,信號量不一定是鎖定某一個資源,而是流程上的概念,比如:有A,B兩個線程,B線程要等A線程完成某一任務以後再進行自己下面的步驟,這個任務並不一定是鎖定某一資源,還可以是進行一些計算或者數據處理之類。而線程互斥量則是「鎖住某一資源」的概念,在鎖定期間內,其他線程無法對被保護的數據進行操作。在有些情況下兩者可以互換。
在linux下, 線程的互斥量數據類型是pthread_mutex_t. 在使用前, 要對它進行初始化:
對於靜態分配的互斥量, 可以把它設置為PTHREAD_MUTEX_INITIALIZER, 或者調用pthread_mutex_init.
對於動態分配的互斥量, 在申請內存(malloc)之後, 通過pthread_mutex_init進行初始化, 並且在釋放內存(free)前需要調用pthread_mutex_destroy.
原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restric attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
頭文件:
返回值: 成功則返回0, 出錯則返回錯誤編號.
說明: 如果使用默認的屬性初始化互斥量, 只需把attr設為NULL. 其他值在以後講解.
首先說一下加鎖函數:
頭文件:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
返回值: 成功則返回0, 出錯則返回錯誤編號.
說 明: 具體說一下trylock函數, 這個函數是非阻塞調用模式, 也就是說, 如果互斥量沒被鎖住, trylock函數將把互斥量加鎖, 並獲得對共享資源的訪問許可權; 如果互斥量 被鎖住了, trylock函數將不會阻塞等待而直接返回EBUSY, 表示共享資源處於忙狀態.
再說一下解所函數:
頭文件:
原型: int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值: 成功則返回0, 出錯則返回錯誤編號.
條件變數常與互斥鎖同時使用,達到線程同步的目的:條件變數通過允許線程阻塞和等待另一個線程發送信號的方法彌補了互斥鎖的不足。在發 送信號時,如果沒有線程 等待在該條件變數上,那麼信號將丟失;而信號量有計數值,每次信號量post操作都會被記錄
1. 互斥鎖必須是誰上鎖就由誰來解鎖,而信號量的wait和post操作不必由同一個線程執行。
2. 互斥鎖要麼被鎖住,要麼被解開,和二值信號量類似
3. sem_post是各種同步技巧中,唯一一個能在信號處理程序中安全調用的函數
4. 互斥鎖是為上鎖而優化的;條件變數是為等待而優化的; 信號量既可用於上鎖,也可用於等待,因此會有更多的開銷和更高的復雜性
5. 互斥鎖,條件變數都只用於同一個進程的各線程間,而信號量(有名信號量)可用於不同進程間的同步。當信號量用於進程間同步時,要求信號量建立在共享內存區。
6. 信號量有計數值,每次信號量post操作都會被記錄,而條件變數在發送信號時,如果沒有線程在等待該條件變數,那麼信號將丟失。
讀寫鎖
讀寫鎖與互斥量類似,不過讀寫鎖允許更高的並行性。互斥量要麼是鎖住狀態要麼是不加鎖狀態,而且一次只有一個線程可以對其加鎖。
讀寫鎖可以由三種狀態:讀模式下加鎖狀態、寫模式下加鎖狀態、不加鎖狀態。一次只有一個線程可以佔有寫模式的讀寫鎖,但是多個線程可以同時佔有讀模式的讀寫
鎖。
在讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖之前,所有試圖對這個鎖加鎖的線程都會被阻塞。當讀寫鎖在讀加鎖狀態時,所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權,但是如果線程希望以寫模式對此鎖進行加鎖,它必須阻塞直到所有的線程釋放讀鎖。雖然讀寫鎖的實現各不相同,但當讀寫鎖處於讀模式鎖住狀態時,如果有另外的線程試圖以寫模式加鎖,讀寫鎖通常會阻塞隨後的讀模式鎖請求。這樣可以避免讀模式鎖長期佔用,而等待的寫模式鎖請求一直得不到滿足。
讀寫鎖非常適合於對數據結構讀的次數遠大於寫的情況。當讀寫鎖在寫模式下時,它所保護的數據結構就可以被安全地修改,因為當前只有一個線程可以在寫模式下擁 有這個鎖。當讀寫鎖在讀狀態下時,只要線程獲取了讀模式下的讀寫鎖,該鎖所保護的數據結構可以被多個獲得讀模式鎖的線程讀取。
讀寫鎖也叫做共享-獨占鎖,當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的;當他以寫模式鎖住時,它是以獨占模式鎖住的。
初始化和銷毀:
#include
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
成功則返回0, 出錯則返回錯誤編號.
同互斥量以上, 在釋放讀寫鎖佔用的內存之前, 需要先通過thread_rwlock_destroy對讀寫鎖進行清理工作, 釋放由init分配的資源.
讀和寫:
#include
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
成功則返回0, 出錯則返回錯誤編號.
這3個函數分別實現獲取讀鎖, 獲取寫鎖和釋放鎖的操作. 獲取鎖的兩個函數是阻塞操作, 同樣, 非阻塞的函數為:
#include
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
成功則返回0, 出錯則返回錯誤編號.
非阻塞的獲取鎖操作, 如果可以獲取則返回0, 否則返回錯誤的EBUSY.
雖然讀寫鎖提高了並行性,但是就速度而言並不比互斥量快.
可能這也是即使有讀寫鎖存在還會使用互斥量的原因,因為他在速度方面略勝一籌。這就需要我們在寫程序的時候綜合考慮速度和並行性並找到一個折中。
比如: 假設使用互斥量需要0.5秒,使用讀寫鎖需要0.8秒。在類似學生管理系統這類軟體中,可能百分之九十的時間都是查詢操作,那麼假如現在突然來個個20個請求,如果使用的是互斥量,那麼最後的那個查詢請求被滿足需要10後。這樣,估計沒人能受得了。而使用讀寫鎖,應為 讀鎖能夠多次獲得。所以所有的20個請求,每個請求都能在1秒左右得到滿足。
也就是說,在一些寫操作比較多或是本身需要同步的地方並不多的程序中我們應該使用互斥量,而在讀操作遠大於寫操作的一些程序中我們應該使用讀寫鎖來進行同步
條件變數(condition)
條件變數與互斥量一起使用時,允許線程以無競爭的方式等待特定的條件發生。
條件本身是由互斥量保護的。線程在改變條件狀態前必須首先鎖住互斥量,其它線程在獲得互斥量之前不會察覺到這種改變,因此必須鎖定互斥量以後才能計算條件。
條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,並釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件
變數,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變數可以被用來實現這兩進程間的線程同步。
1. 初始化:
條件變數採用的數據類型是pthread_cond_t, 在使用之前必須要進行初始化, 這包括兩種方式:
靜態: 可以把常量PTHREAD_COND_INITIALIZER給靜態分配的條件變數.
動態: pthread_cond_init函數, 是釋放動態條件變數的內存空間之前, 要用pthread_cond_destroy對其進行清理.
#include
int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
成功則返回0, 出錯則返回錯誤編號.
注意:條件變數佔用的空間並未被釋放。
當pthread_cond_init的attr參數為NULL時, 會創建一個默認屬性的條件變數; 非默認情況以後討論.
2. 等待條件:
#include
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restric mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);
成功則返回0, 出錯則返回錯誤編號.
這兩個函數分別是阻塞等待和超時等待.
等待條件函數等待條件變為真, 傳遞給pthread_cond_wait的互斥量對條件進行保護, 調用者把鎖住的互斥量傳遞給函數. 函數把調用線程放到等待條件的線程列表上, 然後對互斥量解鎖, 這兩個操作是原子的. 這樣 便關閉了條件檢查和線程進入休眠狀態等待條件改變這兩個操作之間的時間通道, 這樣線程就不會錯過條件的任何變化.
當pthread_cond_wait返回時, 互斥量再次被鎖住.
pthread_cond_wait函數的返回並不意味著條件的值一定發生了變化,必須重新檢查條件的值。
pthread_cond_wait函數返回時,相應的互斥鎖將被當前線程鎖定,即使是函數出錯返回。
阻塞在條件變數上的線程被喚醒以後,直到pthread_cond_wait()函數返回之前條件的值都有可能發生變化。所以函數返回以後,在鎖定相應的互斥鎖之前,必須重新測試條 件值。最好的測試方法是循環調用pthread_cond_wait函數,並把滿足條件的表達式置為循環的終止條件。如:
pthread_mutex_lock();
while (condition_is_false)
pthread_cond_wait();
pthread_mutex_unlock();
阻塞在同一個條件變數上的不同線程被釋放的次序是不一定的。
注意:pthread_cond_wait()函數是退出點,如果在調用這個函數時,已有一個掛起的退出請求,且線程允許退出,這個線程將被終止並開始執行善後處理函數,而這時和條 件變數相關的互斥鎖仍將處在鎖定狀態。
pthread_cond_timedwait函數到了一定的時間,即使條件未發生也會解除阻塞。這個時間由參數abstime指定。函數返回時,相應的互斥鎖往往是鎖定的,即使是函數出錯返回。
注意:pthread_cond_timedwait函數也是退出點。
超時時間參數是指一天中的某個時刻。使用舉例:
pthread_timestruc_t to;
to.tv_sec = time(NULL) + TIMEOUT;
to.tv_nsec = 0;
超時返回的錯誤碼是ETIMEDOUT。
3. 通知條件:
#include
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
成功則返回0, 出錯則返回錯誤編號.
這兩個函數用於通知線程條件已經滿足. 調用這兩個函數, 也稱向線程或條件發送信號. 必須注意, 一定要在改變條件狀態以後再給線程發送信號.
❸ linux線程同步的互斥鎖(mutex)到底怎麼用的》謝謝
互斥鎖(mutex) 通過鎖機制實現線程間的同步。
1、初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
2、靜態分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3、動態分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
4、加好手兆鎖。對共享資源友租的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
intpthread_mutex_lock(pthread_mutex*mutex);
intpthread_mutex_trylock(pthread_mutex_t*mutex);
解鎖。在完成了對共享資源的訪問後,要對互斥量進行解鎖。
intpthread_mutex_unlock(pthread_mutex_t*mutex);
銷毀鎖。鎖在是使用完成後,需要進行銷毀以釋放資源。
intpthread_mutex_destroy(pthread_mutex*mutex);
#include<cstdio>
#include<cstdlib>
#include<unistd.h>
#include<pthread.h>
#include"iostream"
薯賣usingnamespacestd;
pthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;
inttmp;
void*thread(void*arg)
{
cout<<"threadidis"<<pthread_self()<<endl;
pthread_mutex_lock(&mutex);
tmp=12;
cout<<"Nowais"<<tmp<<endl;
pthread_mutex_unlock(&mutex);
returnNULL;
}
intmain()
{
pthread_tid;
cout<<"mainthreadidis"<<pthread_self()<<endl;
tmp=3;
cout<<"Inmainfunctmp="<<tmp<<endl;
if(!pthread_create(&id,NULL,thread,NULL))
{
cout<<"Createthreadsuccess!"<<endl;
}
else
{
cout<<"Createthreadfailed!"<<endl;
}
pthread_join(id,NULL);
pthread_mutex_destroy(&mutex);
return0;
}
//編譯:g++-othreadtestthread.cpp-lpthread
❹ 自旋鎖與互斥鎖
自旋鎖:
是一種用於保護多線程共享資源的鎖,與一般互斥鎖(mutex)不同之處在於當自旋鎖嘗試獲取鎖時以忙等 待(busy waiting)的形式不斷地循環檢查鎖是否可用。當上一個線程的任務沒有執行完畢的時候(被鎖住), 那麼下一個線程會一直等待(不會睡眠),當上一個線程的任務執行完畢,下一個線程會立即執行。
在多 CPU 的環境中,對持有鎖較短的程序來說,使用自旋鎖代替一般的互斥鎖往往能夠提高程序的性能。
互斥鎖:
當上一個線程的任務沒有執行完畢的時候(被鎖住),那麼下一個線程會進入睡眠狀態等待任務執行完畢, 當哪肆上一個線程的任務執行完畢,下一個線程會自動喚醒然後執行任務。
總結:
自旋鎖會忙等: 所謂忙等,即在訪問被鎖資源時,調用者線程不會休眠,而是不停循環在那裡,直到被鎖 資源釋放鎖。
互斥鎖會休眠: 所謂休眠,即在訪問被鎖資源時,調用者線程會休眠,此時 cpu 可以調度其他線程工 作。直到被鎖資源釋放鎖。此時會喚醒休眠線程。
優缺點:
自旋鎖的優點在於,因為自旋鎖不會引起調用者睡眠,所以不伏租會進行線程調度,CPU 時間片輪轉等耗時操 作。所有如果能在很短的時間內獲得鎖,自旋鎖的效率遠高於互斥鎖。
缺點在於,自旋鎖一直佔用 CPU,他在未獲得鎖的情況下,一直運行--自旋,所以佔用著 CPU,如果不 能在很短的時 間內獲得鎖,這無疑會使 CPU 效率降低。自旋鎖不能實現遞歸調用。
自旋鎖:atomic、OSSpinLock、dispatch_semaphore_t
互斥鎖:pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock
鎖的歸類
條件鎖:就是條件變數,當進程的某些資源要求不滿足時就進入休眠,也就
是鎖住了。當資源被分配到了,條件鎖打開,進程繼續運行
NSCondition
NSConditionLock
遞歸鎖:就是同一個線程可以加鎖N次而不會引發死鎖
NSRecursiveLock
pthread_mutex(recursive)
信李廳轎號量(semaphore):是一種更高級的同步機制,互斥鎖可以說是
semaphore在僅取值0/1時的特例。信號量可以有更多的取值空間,用來實
現更加復雜的同步,而不單單是線程間互斥。
dispatch_semaphore
其實基本的鎖就包括了三類 自旋鎖 互斥鎖 讀寫鎖,
其他的比如條件鎖,遞歸鎖,信號量都是上層的封裝和實現!
讀寫鎖
讀寫鎖適合於對數據結構的讀次數比寫次數多得多的情況. 因為, 讀模式鎖定時可以共享, 以寫模式鎖住時意味
著獨占, 所以讀寫鎖又叫共享-獨占鎖.
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
成功則返回0, 出錯則返回錯誤編號.
同互斥量以上, 在釋放讀寫鎖佔用的內存之前, 需要先通過pthread_rwlock_destroy對讀寫鎖進行清理工作, 釋
放由init分配的資源.
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
成功則返回0, 出錯則返回錯誤編號.
這3個函數分別實現獲取讀鎖, 獲取寫鎖和釋放鎖的操作. 獲取鎖的兩個函數是阻塞操作, 同樣, 非阻塞的函數為:
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
成功則返回0, 出錯則返回錯誤編號.
非阻塞的獲取鎖操作, 如果可以獲取則返回0, 否則返回錯誤的EBUSY
❺ 如何保護靜態變數
保護靜態變數的方法有使用互喊喚行斥鎖,使用原子變數,使用局部靜鏈耐態變數。
1、使用互斥鎖:在訪問靜態變數前加鎖,執行完後釋放鎖,確保同一時間只有一個線程可以訪問該變數。
2、使用原子變數:原子變數可鄭嘩以保證自增、自減等操作的原子性,從而避免數據競爭。
3、使用局部靜態變數:將靜態變數放在函數內部作為局部靜態變數,可以避免多個線程同時訪問和修改該變數的問題。
❻ 線程同步互斥鎖和讀寫鎖的區別和各自適用場景
線程同步的方式包括:互斥鎖、讀寫鎖、條件變數、信號量和令牌。互斥鎖和讀寫鎖:提供對臨界資源的保護,當多線程試圖訪問臨界資源時,都必須通過獲取鎖的方式來訪問臨界資源。(臨界資源:是被多線程共享的資源)當讀寫線程獲取鎖的頻率差別不銷物桐大時,一般採用互斥鎖,如果讀線程訪問臨界資源的頻率大於寫線程,這個時候採用讀寫鎖較為合適,讀寫鎖允許多個讀線程同時虧坦訪問臨界資源,讀寫線程必須互斥訪問臨界資源。讀寫鎖的實現螞洞採用了互斥鎖,所以在讀寫次數差不多的情況下採用讀寫鎖性能沒有直接採用互斥鎖來的高。
❼ Linux中 條件變數為什麼要用互斥鎖來保護
你不管他是條件變數還是其他什麼變數。只要理解,因為這個變數/資源是共享的,可能會有多個進程或線程去修改它,那麼就必須為它添加一個鎖,這個鎖是每次只有一個進程/線程可以獲取到的。
打個比方,
mutex是一個布爾型變數,表示這個答宴資源變數(鎖)的一個鑰匙。
為真的是時候表示這個鑰匙當前是可以借,
反之為假的時候表示已經有線程山殲在使用這個鑰匙。
在Java里邊就用關鍵字synchronized來指定一個代碼塊一次只有一個線程可以訪問。
取鑰匙這個函數/方法的演算法就可以這么理解了:如果這個鎖可借,那麼返回真,表示可借;否則返回假表示不可借
public
synchronized
boolean
getmutex(){//取鑰匙
if(mutex==true)//鑰匙空閑可用
{
mutex=false;//取鑰匙就進行修改,證明這一次取鑰匙已經發生
return
true;//返回真,表示取鑰匙成功
}
else
return
false;//這個鑰匙正在被使用,返回假表示去鑰匙失敗
}
就像一個公用電話亭,這就相當於規定了一次只允許一個人進門,你進去了就把門關上。門關著其他人就進不去了,只清唯銀有你打完電話出來開門,釋放這個鎖,其他人才可以進去。
通過synchronized關鍵字將取鑰匙跟進門兩個動作放在在一起,綁在一塊。
其中門就是條件變數,mutex就是這個門的互斥鎖。