iOS多執行緒同步鎖

2021-07-11 21:24:00 字數 4820 閱讀 7597

@synchronized()是在oc**中建立乙個互斥鎖非常方便的方法。@synchronized指令做和其他互斥鎖一樣的工作(它防止不同的執行緒在同一時間獲取同乙個鎖)。然而在這種情況下,你不需要直接建立乙個互斥鎖或鎖物件。相反,你只需要簡單的使用oc物件作為鎖的令牌,如下面例子所示:

- (void)mymethod:(id)anobj  

}

@synchronized()的引數是乙個物件,是用來區別保護塊的唯一標示符。如果你在兩個不同的執行緒裡面執行上述方法,每次在乙個執行緒傳遞了乙個不同的物件給anobj引數,那麼每次都將會擁有它的鎖,並持續處理,中間不被其他執行緒阻塞。然而,如果你傳遞的是同乙個物件,那麼多個執行緒中的乙個執行緒會首先獲得該鎖,而其

他執行緒將會被阻塞直到第乙個執行緒完成它的臨界區。

具體的,編譯器編譯@synchronized包圍的**時,會把這段**編譯成

objc_sync_enter(obj);  

....

objc_sync_exit(obj);

這2個函式的原型,就是

int objc_sync_enter(id obj);

int objc_sync_exit(id obj);

另外因為@synchronized,會確保它包圍的**,如果丟擲異常等,也會呼叫objc_sync_exit等,可能會稍有些效能上的損失。

@synchronized是執行效率最低,但最簡單的乙個directive。建議使用nslock或者osspinlock。

基本用法:

[lock lock]

;[obj yourmethod]

;[lock unlock]

;

執行原理:

某個執行緒a呼叫lock方法。這樣,nslock將被上鎖。可以執行yourmethod,完成後,呼叫unlock方法。

- (bool)lockbeforedate:(nsdate *)limit

在指定的時間以前得到鎖。yes:在指定時間之前獲得了鎖;no:在指定時間之前沒有獲得鎖。該執行緒將被阻塞,直到獲得了鎖,或者指定時間過期。

- (bool)trylock

試圖得到乙個鎖。yes:成功得到鎖;no:沒有得到鎖。

使用nscondition,實現多執行緒的同步,即可實現生產者消費者問題。

問題流程如下:

消費者取得鎖,取產品,如果沒有,則wait,這時會釋放鎖,直到有執行緒喚醒它去消費產品;

生產者製造產品,首先也要取得鎖,然後生產,再發signal,這樣可喚醒wait的消費者。

這裡需要注意wait和signal的問題:

其實,wait函式內部悄悄的呼叫了unlock函式(猜測,有興趣可自行分析),也就是說在呼叫wati函式後,這個nscondition物件就處於了無鎖的狀態,這樣其他執行緒就可以對此物件加鎖並觸發該nscondition物件。當nscondition被其他執行緒觸發時,在wait函式內部得到此事件被觸發的通知,然後對此事件重新呼叫lock函式(猜測),而在外部看起來好像接收事件的執行緒(呼叫wait的執行緒)從來沒有放開nscondition物件的所有權,wati執行緒直接由阻塞狀態進入了觸發狀態一樣。這裡容易造成誤解。

wait函式並不是完全可信的。也就是說wait返回後,並不代表對應的事件一定被觸發了,因此,為了保證執行緒之間的同步關係,使用nscondtion時往往需要加入乙個額外的變數來對非正常的wait返回進行規避。

關於多個wait時的呼叫順序,測試發現與wait執行順序有關。具體請查閱文件。

例項如下:

- (void)producterandconsumer 

- (void)createproducter

[nsthread sleepfortimeinterval:1];

[_products addobject:[nsobject new]];

//喚醒在此nscondition物件上等待的單個執行緒 (通知消費者進行消費)

[_condition signal];

[_condition unlock];

}}- (void)createconsumer

[_products removelastobject];

//喚醒在此nscondition物件上等待的單個執行緒 (通知生產者進行生產)

[_condition signal];

[_condition unlock];

}}

nsconditionlock定義了乙個條件互斥鎖,也就是當條件成立時就會獲取到鎖,反之就會釋放鎖。因為這個特性,條件鎖可以被用在有特定順序的處理流程中,比如生產者-消費者問題。

- (void)producterandconsumerwithconditionlock

- (void)producter

}- (void)consumer

//喚醒在此nscondition物件上等待的單個執行緒 (通知生產者進行生產)

[_conditionlock unlock];

}}

[_conditionlock lockwhencondition:a條件]; 表示如果沒有其他執行緒獲得該鎖,但是該鎖內部的condition不等於a條件,它依然不能獲得鎖,仍然等待。如果內部的condition等於a條件,並且沒有其他執行緒獲得該鎖,則進入**區,同時設定它獲得該鎖,其他任何執行緒都將等待它**的完成,直至它解鎖。

[_conditionlock unlockwithcondition:a條件]; 表示釋放鎖,同時把內部的condition設定為a條件

return = [_conditionlock lockwhencondition:a條件 beforedate:a時間]; 表示如果被鎖定(沒獲得鎖),並超過該時間則不再阻塞執行緒。但是注意:返回的值是no,它沒有改變鎖的狀態,這個函式的目的在於可以實現兩種狀態下的處理

所謂的condition就是整數,內部通過整數比較條件

nsrecursivelock定義的是乙個遞迴鎖,這個鎖可以被同一執行緒多次請求,而不會引起死鎖。遞迴鎖會跟蹤它被lock的次數。每次成功的lock都必須平衡呼叫unlock操作。只有所有達到這種平衡,鎖最後才能被釋放,以供其它執行緒使用。主要用在迴圈或遞迴操作中。

- (void)recursivelockmethod:(int)num

nslog(@"resursivelock unlock");

[_recursivelock unlock];

}

以上所有的鎖都是在解決多執行緒之間的衝突,但如果遇上多個程序或多個程式之間需要構建互斥的情景該怎麼辦呢?這個時候我們就需要使用到nsdistributedlock了,從它的類名就知道這是乙個分布式的lock,nsdistributedlock的實現是通過檔案系統的,所以使用它才可以有效的實現不同程序之間的互斥,但nsdistributedlock並非繼承於nslock,它沒有lock方法,它只實現了trylock,unlock,breaklock,所以如果需要lock的話,你就必須自己實現乙個trylock的輪詢,下面通過**簡單的演示一下吧:

程式a:

dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^);
程式b:
dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^

[lock unlock];

});

dispatch_semaphore 訊號量基於計數器的一種多執行緒同步機制。在多個執行緒訪問共有資源時候,會因為多執行緒的特性而引發資料出錯的問題。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

nsmutablearray *array = [nsmutablearrayarray];

for (int

index = 0; index

< 100000; index++) );

}

dispatch_semaphore_wait(semaphore, dispatch_time_forever)如果semaphore計數大於等於1,將semaphore減1返回,程式繼續執行。如果semaphore計數為0,則等待,此處設定的等待時間是一直等待。dispatch_semaphore_signal(semaphore)將semaphore計數+1。在這兩句**中間的執行**,每次只會允許乙個執行緒進入,這樣就有效的保證了在多執行緒環境下,只能有乙個執行緒進入。

ios/macos自有的自旋鎖,其特點是執行緒等待取鎖時不進核心,執行緒因此不掛起,直接保持空轉,這使得它的鎖操作開銷降得很低,osspinlock是不支援遞迴的。

posix標準的unix多執行緒庫(pthread)中使用的互斥量,支援遞迴,需要特別說明的是訊號機制pthread_cond_wait()同步方式也是依賴於該互斥量,pthread_cond_wait()本身並不具備同步能力。

利用set/get介面的屬性實現原子操作,進而確保「被共享」的變數在多執行緒中讀寫安全,這已經是能滿足部分多執行緒同步要求。

iOS 多執行緒 鎖 互斥 同步

在ios中有幾種方法來解決多執行緒訪問同乙個記憶體位址的互斥同步問題 方法一,synchronized id anobject 最簡單的方法 會自動對引數物件加鎖,保證臨界區內的 執行緒安全 cpp view plain copy print?synchronized self 方法二,nslock...

IOS多執行緒 鎖 互斥 同步

方法一,synchronized id anobject 最簡單的方法 會自動對引數物件加鎖,保證臨界區內的 執行緒安全 synthesize self 方法二,nslock nslock 物件實現了 nslocking protocol 包含幾個方法 lock 加鎖 unlock 解鎖 trylo...

iOS 多執行緒 鎖 互斥 同步

在ios中有幾種方法來解決多執行緒訪問同乙個記憶體位址的互斥同步問題 方法一,synchronized id anobject 最簡單的方法 會自動對引數物件加鎖,保證臨界區內的 執行緒安全 synchronized self 方法二,nslock nslock物件實現了nslocking prot...