這是併發控制方案的系列文章,介紹了各種鎖的使用及優缺點。
OSSpinLock、os_unfair_lock、pthread_mutex_t、pthread_cond_t、pthread_rwlock_t 是值類型,不是引用類型。這意味着使用 = 會進行復制,使用複製的可能導致閃退。pthread 函數認爲其一直處於初始化的內存地址,將其移動到其他內存地址會產生問題。使用copy的OSSpinLock不會崩潰,但會得到一個全新的鎖。
如果你對線程、進程、串行、併發、並行、鎖等概念還不瞭解,建議先查看以下文章:
os_unfair_lock
是一種底層鎖,用於取代OSSpinLock
,嘗試獲取已加鎖的線程無需忙等,解鎖時由內核喚醒。和OSSpinLock
一樣,os_unfair_lock
也沒有加強公平性和順序。例如,釋放鎖的線程可能立即再次加鎖,而之前等待鎖的線程喚醒後沒有機會嘗試加鎖。這樣有利於提高性能,但也造成了飢餓(starvation)。
Starvation 指貪婪線程佔用共享資源太長時間,其他線程無法訪問共享資源、無法取得進展。例如,某對象的同步方法佔用時間過長,並且頻繁調用,其他線程嘗試調用該方法時會被堵塞,處於 starvation。
存儲在鎖中的值應被認爲是不透明的,並且在實現中定義。其包含線程信息,系統可用於解決優先級反轉問題。
1. 初始化os_unfair_lock
os_unfair_lock
結構體包含 unfair lock 數據。
初始化方法如下:
private var moneyLock: os_unfair_lock = os_unfair_lock_s()
private var ticketLock: os_unfair_lock = os_unfair_lock_s()
如果在 Objective-C 中使用
os_unfair_lock
,則應導入#import <os/lock.h>
頭文件。
2. 加鎖os_unfair_lock_lock() os_unfair_lock_trylock()
由於鎖的實現依賴鎖值和擁有鎖進程的地址,因此線程、進程不能通過共享、映射內存地址獲取os_unfair_lock
。
加鎖方法如下:
os_unfair_lock_lock(&moneyLock)
如果鎖已經加鎖,os_unfair_lock_lock()
會休眠,解鎖後由內核喚醒。os_unfair_lock_trylock()
遇到已經加鎖的鎖,會直接返回 false。不要在循環中調用os_unfair_lock_trylock()
函數,os_unfair_lock_lock()
函數已經實現了循環功能。
3. 解鎖os_unfair_lock_unlock()
必須在加鎖的線程調用os_unfair_lock_unlock()
解鎖,從其他線程解鎖會產生運行時錯誤。
解鎖方法如下:
os_unfair_lock_unlock(&moneyLock)
完整的代碼如下:
class OSUnfairLockDemo: BaseDemo {
private var moneyLock: os_unfair_lock = os_unfair_lock_s()
private var ticketLock: os_unfair_lock = os_unfair_lock_s()
override func drawMoney() {
os_unfair_lock_lock(&moneyLock)
super.drawMoney()
os_unfair_lock_unlock(&moneyLock)
}
override func saveMoney() {
os_unfair_lock_lock(&moneyLock)
super.saveMoney()
os_unfair_lock_unlock(&moneyLock)
}
override func saleTicket() {
os_unfair_lock_lock(&ticketLock)
super.saleTicket()
os_unfair_lock_unlock(&ticketLock)
}
}
通常,應優先選擇使用高級同步工具。如 pthread、dispatch 等提供的同步方案。
Demo名稱:Synchronization
源碼地址:https://github.com/pro648/BasicDemos-iOS/tree/master/Synchronization
上一篇:線程同步之自旋鎖
下一篇:線程同步之互斥鎖
參考資料: