談?wù)刬OS中的幾種鎖
1 前言
近日工作不是太忙,剛好有時間了解一些其他東西,本來打算今天上午去體檢,但是看看天氣還是明天再去吧,也有很大一個原因:就是周六沒有預(yù)約上!閑話少說,這里簡單對鎖來個簡單介紹分享。
2 目錄
- 第一部分:什么是鎖
- 第二部分:鎖的分類
- 第三部分:鎖的作用
- 第四部分:iOS中鎖的實現(xiàn)
第一部分:什么是鎖
從小就知道鎖,就是家里門上的那個鎖,用來防止盜竊的鎖。它還有鑰匙,用于開鎖。不過這里的鎖,并不是小時候認(rèn)知的鎖,而是站在程序員的角度的鎖。這里我就按照我的理解來介紹一下鎖。
在計算機科學(xué)中,鎖是一種同步機制,用于在存在多線程的環(huán)境中實施對資源的訪問限制。你可以理解成它用于排除并發(fā)的一種策略??蠢?br />
if (lock == 0) { lock = myPID; }
上面這段代碼并不能保證這個任務(wù)有個鎖,因此它可以在同一時間被多個任務(wù)執(zhí)行。這個時候就有可能多個任務(wù)都檢測到lock是空閑的,因此兩個或者多個任務(wù)都將嘗試設(shè)置lock,而不知道其他的任務(wù)也在嘗試設(shè)置lock。這個時候就會出問題了。
再看看這段代碼:
class Acccount { long val = 0; //這里不可在其他方法修改,只能通過add/minus修改 object thisLock = new object(); public void add(const long x) { lock(thisLock) { val +=x; } } public void minus(const long x) { lock(thisLock) { val -=x; } } }
這樣就能防止多個任務(wù)去修改val了,(這里注意,如果val是public的,那個也會導(dǎo)致一些問題)。
第二部分:鎖的分類
鎖根據(jù)不同的性質(zhì)可以分成不同的類。
在WiKiPedia介紹中,一般的鎖都是建議鎖,也就四每個任務(wù)去訪問公共資源的時候,都需要取得鎖的資訊,再根據(jù)鎖資訊來確定是否可以存取。若存取對應(yīng)資訊,鎖的狀態(tài)會改變?yōu)殒i定,因此其他線程不會訪問該資源,當(dāng)結(jié)束訪問時,鎖會釋放,允許其他任務(wù)訪問。有些系統(tǒng)有強制鎖,若未經(jīng)授權(quán)的鎖訪問鎖定的資料,在訪問時就會產(chǎn)生異常。
在iOS中,鎖分為遞歸鎖、條件鎖、分布式鎖、一般鎖(這里是看著NSLock類里面的分類劃分的)。
對于數(shù)據(jù)庫的鎖分類:
分類方式 | 分類 |
---|---|
按鎖的粒度劃分 | 表級鎖、行級鎖、頁級鎖 |
按鎖的級別劃分 | 共享鎖、排他鎖 |
按加鎖方式劃分 | 自動鎖、顯示鎖 |
按鎖的使用方式劃分 | 樂觀鎖、悲觀鎖 |
按操作劃分 | DML鎖、DDL鎖 |
這里就不在詳細(xì)介紹了,感興趣的大家可以自己查閱相關(guān)資料。
第三部分:鎖的作用
這個比較通俗來講:就是為了防止在多線程(多任務(wù))的情況下對共享資源(臨界資源)的臟讀或者臟寫。也可以理解為:執(zhí)行多線程時用于強行限制資源訪問的同步機制,即并發(fā)控制中保證互斥的要求。
第四部分:iOS中鎖的實現(xiàn)
先看看iOS中NSLock類的.h文件。這里就不在寫上來了。從代碼中可以看出,該類分成了幾個子類:NSLock、NSConditionLock、NSRecursiveLock以及NSCondition。然后有一個NSLocking的協(xié)議:
@protocol NSLocking - (void)lock; - (void)unlock; @end
這幾個子類都遵循了NSLock的協(xié)議,這里簡單介紹一下其中的幾個方法:
對于tryLock方法,嘗試獲取一個鎖,并且立刻返回Bool值,YES表示獲取了鎖,NO表示沒有獲取鎖失敗。 lockBeforeDate:方法,在某個時刻之前獲取鎖,如果獲取成功,則返回YES,NO表示獲取鎖失敗。接下來就讓我們看一下iOS中實現(xiàn)鎖的方式:
方式1 使用NSLock類
- (void)nslockDemo { NSLock *myLock = [[NSLock alloc] init]; _testLock = [[TestLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [myLock lock]; [_testLock method1]; sleep(5); [myLock unlock]; if ([myLock tryLock]) { NSLog(@"可以獲得鎖"); }else { NSLog(@"不可以獲得所"); } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); if ([myLock tryLock]) { NSLog(@"---可以獲得鎖"); }else { NSLog(@"----不可以獲得所"); } [myLock lock]; [_testLock method2]; [myLock unlock]; }); }
方式2 使用@synchorize
- (void)synchronizeDemo { _testLock = [[TestLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized (_testLock) { [_testLock method1]; sleep(5); } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); @synchronized (_testLock) { [_testLock method2]; } }); }
對于synchorize指令中使用的testLock為該鎖標(biāo)示,只有標(biāo)示相同的時候才滿足鎖的效果。它的優(yōu)點是不用顯式地創(chuàng)建鎖,便可以實現(xiàn)鎖的機制。但是它會隱式地添加異常處理程序來保護代碼,該程序在拋出異常的時候自動釋放鎖。
方式3 使用gcd
- (void)gcdDemo { _testLock = [[TestLock alloc] init]; dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [_testLock method1]; sleep(5); dispatch_semaphore_signal(semaphore); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [_testLock method2]; dispatch_semaphore_signal(semaphore); }); }
方式4 使用phtread
- (void)pthreadDemo { _testLock = [[TestLock alloc] init]; __block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); //線程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&mutex); [_testLock method1]; sleep(5); pthread_mutex_unlock(&mutex); }); //線程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); pthread_mutex_lock(&mutex); [_testLock method2]; pthread_mutex_unlock(&mutex); }); }
pthread_mutex_t定義在pthread.h,所以記得#include。
3 性能對比
這里簡單寫一個小程序來進(jìn)行四種方式的性能對比,這里再固定次數(shù)內(nèi)進(jìn)行了加鎖解鎖,然后輸出用時,結(jié)果如下(測試1、2執(zhí)行次數(shù)不一樣:測試1 < 測試2):
測試1
2016-11-05 15:27:52.595 LockDemo[4394:202297] NSLock times:0.871843
2016-11-05 15:27:56.335 LockDemo[4394:202297] synthorize times:3.738939
2016-11-05 15:27:56.691 LockDemo[4394:202297] gcd times:0.355344
2016-11-05 15:27:57.328 LockDemo[4394:202297] pthread times:0.636815
2016-11-05 15:27:57.559 LockDemo[4394:202297] OSSPinLock times:0.231013
2016-11-05 15:27:57.910 LockDemo[4394:202297] os_unfair_lock times:0.350615
測試2
2016-11-05 15:30:54.123 LockDemo[4454:205180] NSLock times:1.908103
2016-11-05 15:31:02.112 LockDemo[4454:205180] synthorize times:7.988547
2016-11-05 15:31:02.905 LockDemo[4454:205180] gcd times:0.792113
2016-11-05 15:31:04.372 LockDemo[4454:205180] pthread times:1.466987
2016-11-05 15:31:04.870 LockDemo[4454:205180] OSSPinLock times:0.497487
2016-11-05 15:31:05.637 LockDemo[4454:205180] os_unfair_lock times:0.767569
這里還測試了OSSPinLock(此類已經(jīng)被os_unfair_lock所替代)。結(jié)果如下:
synthorize > NSLock > pthread > gcd > os_unfair_lock >OSSPinLock
這里:
synthorize內(nèi)部會添加異常處理,所以耗時。
pthread_mutex底層API,處理能力不錯。
gcd系統(tǒng)封裝的C代碼效果比pthread好。
4 總結(jié)
簡單就介紹這么多。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS 中根據(jù)屏幕寬度自適應(yīng)分布按鈕的實例代碼
這篇文章主要介紹了iOS 中根據(jù)屏幕寬度自適應(yīng)分布按鈕的實例代碼,本文給大家分享兩種方式,代碼簡單易懂,需要的朋友可以參考下2016-11-11IOS開發(fā)代碼分享之用nstimer實現(xiàn)倒計時功能
在制作IOS項目中,我們經(jīng)常要用到倒計時功能,今天就分享下使用nstimer實現(xiàn)的倒計時功能的代碼,希望對大家能有所幫助2014-09-09iOS實現(xiàn)列表與網(wǎng)格兩種視圖的相互切換
相信大家應(yīng)該也都發(fā)現(xiàn)了,在現(xiàn)在很多的電商app中,都會有列表視圖和網(wǎng)格兩種視圖的相互切換。例如京東和淘寶。這樣更利于提高用戶的體驗度,所以這篇文章小編就是大家分享下利用iOS實現(xiàn)列表與網(wǎng)格兩種視圖相互切換的方法,文中介紹的很詳細(xì),感興趣的下面來一起看看吧。2016-10-102016 cocoapods的安裝和使用方法以及版本升級遇到的問題
CocoaPods是一個負(fù)責(zé)管理iOS項目中第三方開源庫的工具,通過CocoaPods,我們可以將第三方的依賴庫統(tǒng)一管理起來,配置和更新只需要通過簡單的幾行命令即可完成,需要的朋友可以參考下2016-09-09iOS開發(fā)中使用UIWebView 屏蔽 alert警告框
這篇文章主要介紹了iOS開發(fā)中使用UIWebView 屏蔽 alert警告框的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11iOS開發(fā)系列--詳細(xì)介紹數(shù)據(jù)存取
本篇文章主要介紹了iOS開發(fā)系列--詳細(xì)介紹數(shù)據(jù)存取,詳細(xì)介紹了IOS數(shù)據(jù)的存儲問題,具有一定的參考價值,有興趣的同學(xué)可以了解一下。2016-11-11