iOS 中的各種鎖

2021-09-08 12:17:41 字數 4836 閱讀 2182

在日常開發過程中,為了提公升程式執行效率,以及使用者體驗,我們經常使用多執行緒。在使用多執行緒的過程中,難免會遇到資源競爭問題。我們採用鎖的機制來確保執行緒安全。

執行緒安全

當乙個執行緒訪問資料的時候,其他的執行緒不能對其進行訪問,直到該執行緒訪問完畢。即,同一時刻,對同乙個資料操作的執行緒只有乙個。只有確保了這樣,才能使資料不會被其他執行緒汙染。而執行緒不安全,則是在同一時刻可以有多個執行緒對該資料進行訪問,從而得不到預期的結果。

比如寫檔案和讀檔案,當乙個執行緒在寫檔案的時候,理論上來說,如果這個時候另乙個執行緒來直接讀取的話,那麼得到將是不可預期的結果。

為了執行緒安全,我們可以使用鎖的機制來確保,同一時刻只有同乙個執行緒來對同乙個資料來源進行訪問。在開發過程中我們通常使用以下幾種鎖。

nslock

nsrecursivelock

nscondition

nsconditionlock

pthread_mutex

pthread_rwlock

posix conditions

osspinlock

os_unfair_lock

dispatch_semaphore

@synchronized

訊號量在多執行緒環境下用來確保**不會被併發呼叫。在進入一段**前,必須獲得乙個訊號量,在結束**前,必須釋放該訊號量,其他想要想要執行該**的執行緒必須等待直到前者釋放了該訊號量。

以乙個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然後放落車攔,剩下的車則必須在入口等待,此後來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知後,開啟車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。

在這個停車場系統中,車位是公共資源,每輛車好比乙個執行緒,看門人起的就是訊號量的作用。

互斥鎖一種用來防止多個執行緒同一時刻對共享資源進行訪問的訊號量,它的原子性確保了如果乙個執行緒鎖定了乙個互斥量,將沒有其他執行緒在同一時間可以鎖定這個互斥量。它的唯一性確保了只有它解鎖了這個互斥量,其他執行緒才可以對其進行鎖定。當乙個執行緒鎖定乙個資源的時候,其他對該資源進行訪問的執行緒將會被掛起,直到該執行緒解鎖了互斥量,其他執行緒才會被喚醒,進一步才能鎖定該資源進行操作。

nslock

nslock實現了最基本的互斥鎖,遵循了 nslocking 協議,通過 lock 和 unlock 來進行鎖定和解鎖。其使用也非常簡單

- (void)dosomething
由於是互斥鎖,當乙個執行緒進行訪問的時候,該執行緒獲得鎖,其他執行緒進行訪問的時候,將被作業系統掛起,直到該執行緒釋放鎖,其他執行緒才能對其進行訪問,從而卻確保了執行緒安全。但是如果連續鎖定兩次,則會造成死鎖問題。那如果想在遞迴中使用鎖,那要怎麼辦呢,這就用到了 nsrecursivelock 遞迴鎖。

nsrecursivelock

遞迴鎖,顧名思義,可以被乙個執行緒多次獲得,而不會引起死鎖。它記錄了成功獲得鎖的次數,每一次成功的獲得鎖,必須有乙個配套的釋放鎖和其對應,這樣才不會引起死鎖。只有當所有的鎖被釋放之後,其他執行緒才可以獲得鎖

nsrecursivelock *thelock = [[nsrecursivelock alloc] init];

void myrecursivefunction(int value)    [thelock unlock]; } myrecursivefunction(5);

nscondition 

- (void)download  }

- (void)dostuffwithdownloadpicture    //todo: 處理**    [self.condition unlock]; }

nsconditionlock

nsconditionlock 物件所定義的互斥鎖可以在使得在某個條件下進行鎖定和解鎖。它和 nscondition 很像,但實現方式是不同的。

當兩個執行緒需要特定順序執行的時候,例如生產者消費者模型,則可以使用 nsconditionlock 。當生產者執行執行的時候,消費者可以通過特定的條件獲得鎖,當生產者完成執行的時候,它將解鎖該鎖,然後把鎖的條件設定成喚醒消費者執行緒的條件。鎖定和解鎖的呼叫可以隨意組合,lock 和 unlockwithcondition: 配合使用 lockwhencondition: 和 unlock 配合使用。

- (void)producer  } - (void)consumer  }
當生產者釋放鎖的時候,把條件設定成了1。這樣消費者可以獲得該鎖,進而執行程式,如果消費者獲得鎖的條件和生產者釋放鎖時給定的條件不一致,則消費者永遠無法獲得鎖,也不能執行程式。同樣,如果消費者釋放鎖給定的條件和生產者獲得鎖給定的條件不一致的話,則生產者也無法獲得鎖,程式也不能執行。

pthread_mutex

posix 互斥鎖是一種超級易用的互斥鎖,使用的時候,只需要初始化乙個 pthread_mutex_t 用 pthread_mutex_lock 來鎖定 pthread_mutex_unlock 來解鎖,當使用完成後,記得呼叫 pthread_mutex_destroy 來銷毀鎖。

pthread_mutex_init(&lock,null);

pthread_mutex_lock(&lock);

//do your stuff

pthread_mutex_unlock(&lock);    pthread_mutex_destroy(&lock);

pthread_rwlock 

讀寫鎖,在對檔案進行操作的時候,寫操作是排他的,一旦有多個執行緒對同乙個檔案進行寫操作,後果不可估量,但讀是可以的,多個執行緒讀取時沒有問題的。

// 初始化

pthread_rwlock_t rwlock = pthread_rwlock_initializer

// 讀模式

pthread_rwlock_wrlock(&lock);

// 寫模式

pthread_rwlock_rdlock(&lock);

// 讀模式或者寫模式的解鎖

pthread_rwlock_unlock(&lock);

dispatch_async(dispatch_get_global_queue(0, 0), ^);    dispatch_async(dispatch_get_global_queue(0, 0), ^);    dispatch_async(dispatch_get_global_queue(0, 0), ^);    dispatch_async(dispatch_get_global_queue(0, 0), ^);    dispatch_async(dispatch_get_global_queue(0, 0), ^); - (void)readbookwithtag:(nsinteger )tag  - (void)writebook:(nsinteger)tag 

posix conditions 

posix 條件鎖需要互斥鎖和條件兩項來實現,雖然看起來沒什麼關係,但在執行時中,互斥鎖將會與條件結合起來。執行緒將被乙個互斥和條件結合的訊號來喚醒。

首先初始化條件和互斥鎖,當 ready_to_go 為 flase 的時候,進入迴圈,然後執行緒將會被掛起,直到另乙個執行緒將 ready_to_go 設定為 true 的時候,並且傳送訊號的時候,該執行緒會才被喚醒。

pthread_mutex_t mutex;pthread_cond_t condition;

boolean ready_to_go = true;void mycondinitfunction()void mywaitonconditionfunction()        ready_to_go = false;    pthread_mutex_unlock(&mutex); }void signalthreadusingcondition()

osspinlock

自旋鎖,和互斥鎖類似,都是為了保證執行緒安全的鎖。但二者的區別是不一樣的,對於互斥鎖,當乙個執行緒獲得這個鎖之後,其他想要獲得此鎖的執行緒將會被阻塞,直到該鎖被釋放。但自選鎖不一樣,當乙個執行緒獲得鎖之後,其他執行緒將會一直迴圈在**檢視是否該鎖被釋放。所以,此鎖比較適用於鎖的持有者儲存時間較短的情況下。

// 初始化

spinlock = os_spinlock_init;

// 加鎖

osspinlocklock(&spinlock);

// 解鎖

osspinlockunlock(&spinlock);

然而,yykit 作者 @ibireme 的文章也有說這個自旋鎖存在優先順序反轉問題,具體文章: 不再安全的 osspinlock 。( )

os_unfair_lock

自旋鎖已經不在安全,然後蘋果又整出來個 os_unfair_lock_t (╯‵□′)╯︵┻━┻

這個鎖解決了優先順序反轉問題。

os_unfair_lock_t unfairlock;

unfairlock = &(os_unfair_lock_init);

os_unfair_lock_lock(unfairlock);

os_unfair_lock_unlock(unfairlock);

dispatch_semaphore 

訊號量機制實現鎖,等待訊號,和傳送訊號,正如前邊所說的看門人一樣,當有多個執行緒進行訪問的時候,只要有乙個獲得了訊號,其他執行緒的就必須等待該訊號釋放。

- (void)semphone:(nsinteger)tag
@synchronized

乙個便捷的建立互斥鎖的方式,它做了其他互斥鎖所做的所有的事情。

如果你在不同的執行緒中傳過去的是一樣的識別符號,先獲得鎖的會鎖定**塊,另乙個執行緒將被阻塞,如果傳遞的是不同的識別符號,則不會造成執行緒阻塞。

總結應當針對不同的操作使用不同的鎖,而不能一概而論那種鎖的加鎖解鎖速度快。

python鎖 python中的各種鎖

一 全域性直譯器鎖 gil 1 什麼是全域性直譯器鎖 在同乙個程序中只要有乙個執行緒獲取了全域性直譯器 cpu 的使用許可權,那麼其他的執行緒就必須等待該執行緒的全域性直譯器 cpu 使 用權消失後才能使用全域性直譯器 cpu 即時多個執行緒直接不會相互影響在同乙個程序下也只有乙個執行緒使用cpu,...

java中的各種鎖

在 jdk 1.6 之前,synchronized 是重量級鎖,效率低下。從 jdk 1.6 開始,synchronized 做了很多優化,如偏向鎖 輕量級鎖 自旋鎖 適應性自旋鎖 鎖消除 鎖粗化等技術來減少鎖操作的開銷。synchronized 同步鎖一共包含四種狀態 無鎖 偏向鎖 輕量級鎖 重量...

併發中的各種鎖

1.執行緒是否要鎖住同步資源 鎖住 悲觀鎖 不鎖住 樂觀鎖 2.鎖住同步資源失敗執行緒是否要阻塞 不阻塞 自旋鎖 適應性自旋鎖 3.synchronized關鍵字優化之後的幾個狀態流 無鎖 偏向鎖 輕量級鎖 重量級鎖 4.多個執行緒競爭鎖時是否排隊 排隊 公平鎖 先嘗試插隊 直接搶鎖 插隊失敗再排隊...