我只是一個(gè)搬運(yùn)工,僅僅為了加深記憶,感謝作者分享,文章大部分來源:尚大大o_O
線程和進(jìn)程
幾乎所有的操作系統(tǒng)都支持同時(shí)運(yùn)行多個(gè)任務(wù),一個(gè)任務(wù)通常就是一個(gè)程序,每個(gè)程序就是一個(gè)進(jìn)程。當(dāng)一個(gè)程序運(yùn)行時(shí),內(nèi)部可能包含了多個(gè)順序執(zhí)行流,每個(gè)順序執(zhí)行流就是一個(gè)線程。
- 進(jìn)程(Process )
當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行后,即變成一個(gè)進(jìn)程。進(jìn)程是處于是處于運(yùn)行過程中的程序,并且具有一定的獨(dú)立功能,進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。一般而言,進(jìn)程有如下特征:
- 獨(dú)立性:有自己獨(dú)立的資源,且擁有自己私有的地址空間。在沒有經(jīng)過進(jìn)程本省的允許下,其他進(jìn)程是不能直接訪問其進(jìn)程的地址空間的。
- 動(dòng)態(tài)性:程序只是靜態(tài)的指令集合,而進(jìn)程是一個(gè)正在系統(tǒng)中活動(dòng)的指令集合。進(jìn)程有時(shí)間的概念,具有自己的生命周期和各種狀態(tài)。
- 并發(fā)性:多個(gè)進(jìn)程可以在單個(gè)處理器上并發(fā)執(zhí)行,互相不會(huì)影響。
- 線程(Thread)
線程也被稱做輕量級(jí)進(jìn)程,線程是進(jìn)程的執(zhí)行單元。就像進(jìn)程在系統(tǒng)中一樣,線程在進(jìn)程中也是獨(dú)立的,并發(fā)的執(zhí)行流程。一個(gè)進(jìn)程可以擁有多個(gè)線程,一個(gè)線程必須有一個(gè)父進(jìn)程,但不再擁有系統(tǒng)資源,而是和父進(jìn)程一起共享父進(jìn)程的全部資源。多線程由于共享父進(jìn)程的資源,所以編程更加方便,但是也需要小心線程不會(huì)影響到父進(jìn)程中的其他線程。線程是獨(dú)立運(yùn)行的,它并不知道其他線程的存在。線程執(zhí)行是搶占式的,也就是說,當(dāng)前運(yùn)行的線程在任何時(shí)候都可能被掛起,以便林另外一個(gè)線程可以運(yùn)行。
- 多線程優(yōu)點(diǎn)
- 進(jìn)程間不可以共享內(nèi)存,但線程之間共享內(nèi)存十分容易。
- 系統(tǒng)創(chuàng)建進(jìn)程需要為其重新分配系統(tǒng)資源,但是創(chuàng)建線程代價(jià)小得多,因此效率更高
為什么要用多線程編程
為了提高資源利用率來提升系統(tǒng)整體效率,實(shí)際往往是將耗時(shí)操作放在后臺(tái)執(zhí)行,避免阻塞主線程,在iOS中UI繪制和用戶響應(yīng)都是主線程。
NSThread
常用API
- (void)viewDidLoad {
[super viewDidLoad];
//打印當(dāng)前線程
NSLog(@"開始:%@ 優(yōu)先級(jí):%d", [NSThread currentThread], [NSThread currentThread].qualityOfService);
//1.創(chuàng)建NSTread對(duì)象,必須調(diào)用start方法開始,并且只能傳一個(gè)參數(shù)object
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"test"];
// NSThread *thread = [[NSThread alloc] initWithBlock:^{}];
thread.name = @"testThread";
thread.qualityOfService = NSQualityOfServiceUserInteractive;
[thread start];
//2.直接創(chuàng)建并啟動(dòng)線程
// [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"test"];
// [NSThread detachNewThreadWithBlock:^{}];
//3.隱式直接創(chuàng)建
// [NSThread performSelectorInBackground:@selector(run:) withObject:nil];
// NSLog(@"結(jié)束:%@", [NSThread currentThread]);
}
- (void)run:(NSObject *)object {
//阻塞休眠
// [NSThread sleepForTimeInterval:5];
//中止當(dāng)前線程
// [NSThread exit];
NSLog(@"子線程運(yùn)行:%@ %@ 優(yōu)先級(jí):%d", [NSThread currentThread], object, [NSThread currentThread].qualityOfService);
}
復(fù)制代碼
- 線程的狀態(tài)
線程被啟動(dòng)后,并不是直接進(jìn)入執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài),由于線程并發(fā),線程會(huì)反復(fù)在運(yùn)行、就緒間切換。創(chuàng)建一個(gè)線程后,處于新建狀態(tài),系統(tǒng)為其分配內(nèi)存,初始化成員變量;調(diào)用-(void)start;方法后,該線程處于就緒狀態(tài),系統(tǒng)為其創(chuàng)建方法調(diào)用棧和程序計(jì)數(shù)器,此時(shí)并沒有運(yùn)行,何時(shí)運(yùn)行取決于系統(tǒng)調(diào)度。
[圖片上傳中...(image-ce30cc-1577264887488-0)]
<figcaption></figcaption>
- 終止子線程
每個(gè)線程都有一定的優(yōu)先級(jí),優(yōu)先級(jí)越高獲得執(zhí)行機(jī)會(huì)越多。目前通過qualityOfService屬性來設(shè)置,原來的threadPriority由于語義不夠清晰,已經(jīng)被廢棄了。
NSQualityOfServiceUserInteractive:最高優(yōu)先級(jí),主要用于提供交互UI的操作,比如處理點(diǎn)擊事件,繪制圖像到屏幕上
NSQualityOfServiceUserInitiated:次高優(yōu)先級(jí),主要用于執(zhí)行需要立即返回的任務(wù)
NSQualityOfServiceDefault:默認(rèn)優(yōu)先級(jí),當(dāng)沒有設(shè)置優(yōu)先級(jí)的時(shí)候,線程默認(rèn)優(yōu)先級(jí)
NSQualityOfServiceUtility:普通優(yōu)先級(jí),主要用于不需要立即返回的任務(wù)
NSQualityOfServiceBackground:后臺(tái)優(yōu)先級(jí),用于完全不緊急的任務(wù)
復(fù)制代碼
- 缺點(diǎn)
使用NSThread進(jìn)行多線程編程較復(fù)雜,需要自己控制多線程的同步、并發(fā),還需要自己控制線程的終止銷毀,稍有不留神容易出現(xiàn)錯(cuò)誤,對(duì)開發(fā)者要求較高,一般較少使用。
NSOperation
iOS還提供了NSOperation與NSOperationQueue來實(shí)現(xiàn)多線程,是基于GCD更高一層的封裝,完全面向?qū)ο蟆5荊CD更簡(jiǎn)單易用、代碼可讀性也更高。
NSOperationQueue:負(fù)責(zé)管理系統(tǒng)提交的多個(gè)NSOperation,底層維護(hù)了一個(gè)線程池。不同于GCD中的調(diào)度隊(duì)列FIFO(先進(jìn)先出)原則。NSOperationQueue對(duì)于添加到隊(duì)列中的操作,首先進(jìn)入準(zhǔn)備就緒的狀態(tài)(就緒狀態(tài)取決于操作之間的依賴關(guān)系),然后進(jìn)入就緒狀態(tài)的操作的開始執(zhí)行順序(非結(jié)束執(zhí)行順序)由操作之間相對(duì)的優(yōu)先級(jí)決定(優(yōu)先級(jí)是操作對(duì)象自身的屬性)。
NSOperation: 代表一個(gè)多線程任務(wù)。
- 為什么要使用NSOperation、NSOPerationQueue?
- 可以添加完成的代碼塊,在操作完成后執(zhí)行。
- 添加操作之間的依賴關(guān)系,方便的控制執(zhí)行順序。
- 設(shè)定操作執(zhí)行的優(yōu)先級(jí)。
- 可以很方便的取消一個(gè)操作的執(zhí)行。
- 使用KVO觀察對(duì)操作執(zhí)行狀態(tài)的更改:isExecuteing、isFinished、isCancelled。
- 常用API
NSOperationQueue *queue;
//獲取執(zhí)行當(dāng)前NSOperation的NSOperationQueue隊(duì)列
// queue = [NSOperationQueue currentQueue];
//獲取主線程的NSOperationQueue隊(duì)列
// queue = [NSOperationQueue mainQueue];
//自定義隊(duì)列
queue = [[NSOperationQueue alloc] init];
//隊(duì)列名
queue.name = @"testOperationQueue";
//最大并發(fā)操作數(shù)(系統(tǒng)有限制,即使設(shè)置很大,也會(huì)自動(dòng)調(diào)整)
queue.maxConcurrentOperationCount = 10;
//設(shè)置優(yōu)先級(jí)
queue.qualityOfService = NSQualityOfServiceDefault;
//自定義NSOperation,如果SEL和Block為空,系統(tǒng)不會(huì)加入到指定隊(duì)列
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation");
}];
//添加依賴關(guān)系,invocationOperation執(zhí)行完后才執(zhí)行blockOperation
[blockOperation addDependency:invocationOperation];
//添加到隊(duì)列中
// [queue addOperation:invocationOperation];
[queue addOperations:@[invocationOperation, blockOperation] waitUntilFinished:NO];
//直接添加代碼塊任務(wù)
[queue addOperationWithBlock:^{
}];
//打印所有的NSOperation
for(int i=0; i<queue.operationCount; i++) {
NSLog(@"隊(duì)列%@的第%d個(gè)NSOperation:%@", queue.name, i, queue.operations[i]);
}
//終止所有NSOperation
// [queue cancelAllOperations];
//執(zhí)行完所有NSOperation才能解除阻塞當(dāng)前線程
// [queue waitUntilAllOperationsAreFinished];
復(fù)制代碼
GCD(Grand Central Dispatch)
- 基本概念
- 隊(duì)列:隊(duì)列負(fù)責(zé)開發(fā)者提交的任務(wù),不過不同任務(wù)的執(zhí)行時(shí)間不一樣,先處理的任務(wù)不一定先完成。隊(duì)列即可是串行的,也可是并行的,隊(duì)列底層會(huì)維持一個(gè)線程池來處理任務(wù),串行隊(duì)列只需要維護(hù)一個(gè)線程即可,并行隊(duì)列則需要維護(hù)多個(gè)線程。
- 任務(wù):用戶提交給隊(duì)列的工作單元,這些任務(wù)將會(huì)提交給隊(duì)列底層維護(hù)的線程池。
- 異步:可以在新的線程中執(zhí)行任務(wù),但不一定會(huì)開辟新的線程。dispatch函數(shù)會(huì)立即返回,然后Block在后臺(tái)異步執(zhí)行。
- 同步:在當(dāng)前線程執(zhí)行任務(wù),不會(huì)開辟新的線程。必須等到Block函數(shù)執(zhí)行完畢后,dispatch函數(shù)才會(huì)返回。
注:隊(duì)列的串行和并行決定了任務(wù)以何種方式執(zhí)行,執(zhí)行的異步和同步?jīng)Q定了是否需要開辟新線程處理任務(wù)。
- 特點(diǎn)
- GCD可用于多核的并行運(yùn)算;
- GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核);
- GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程);
- 程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要寫任何線程管理代碼;
- 常用API
/** 獲取隊(duì)列 */
//獲取指定優(yōu)先級(jí)的全局并發(fā)隊(duì)列(flag填0即可,僅預(yù)留的參數(shù),使用其他值可能會(huì)返回null)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建自定義并行隊(duì)列
dispatch_queue_t queue1 = dispatch_queue_create("testQueue1", DISPATCH_QUEUE_CONCURRENT);
//獲取系統(tǒng)主線程關(guān)聯(lián)的串行隊(duì)列
dispatch_queue_t queue2 = dispatch_get_main_queue();
//創(chuàng)建自定義串行隊(duì)列
dispatch_queue_t queue3 = dispatch_queue_create("testQueue3", DISPATCH_QUEUE_SERIAL);
/** 提交任務(wù) */
//異步提交代碼塊到并發(fā)隊(duì)列
dispatch_async(queue, ^{
});
//同步提交代碼塊到自定義并發(fā)隊(duì)列
dispatch_sync(queue1, ^{
});
//異步提交代碼塊到串行隊(duì)列,線程池將在指定時(shí)間執(zhí)行代碼塊(實(shí)際是5秒后加入到隊(duì)列中,實(shí)際并不一定會(huì)立馬執(zhí)行,一般精度要求下是沒問題的)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)), queue2, ^{
});
//異步提交代碼到自定義串行隊(duì)列,同步函數(shù),無論是在串行還是并行隊(duì)列中執(zhí)行,都要執(zhí)行完才返回,所以要防止線程阻塞和死鎖,time表示當(dāng)前是第幾次(如果提交給并發(fā)隊(duì)列,會(huì)啟動(dòng)五個(gè)線程來執(zhí)行)
dispatch_apply(5, queue3, ^(size_t time) {
});
//實(shí)際是個(gè)long類型變量,用于判斷該代碼塊是否被執(zhí)行過
static dispatch_once_t onceToken;
//主線程執(zhí)行一次代碼塊
dispatch_once(&onceToken, ^{
});
//等group執(zhí)行完后,才能執(zhí)行下一步
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
/** 組(用于需要等待多個(gè)任務(wù)全部執(zhí)行完再進(jìn)行下一步) */
dispatch_group_t group = dispatch_group_create();
//并發(fā)執(zhí)行的代碼塊1
dispatch_group_async(group, queue, ^{
});
//并發(fā)執(zhí)行的代碼塊2
dispatch_group_async(group, queue, ^{
});
//等待兩個(gè)代碼塊執(zhí)行完匯總
dispatch_group_notify(group, queue, ^{
});
/** 柵欄(用于需要依次執(zhí)行完多個(gè)線程組) */
//并發(fā)隊(duì)列異步執(zhí)行代碼塊1,2
dispatch_async(queue, ^{
//代碼塊1
});
dispatch_async(queue, ^{
//代碼塊2
});
//1,2執(zhí)行完后才會(huì)執(zhí)行3,4
dispatch_barrier_async(queue, ^{
});
//并發(fā)隊(duì)列異步執(zhí)行代碼塊3,4
dispatch_async(queue, ^{
//代碼塊3
});
dispatch_async(queue, ^{
//代碼塊4
});
/** 信號(hào)量(用于控制線程的等待和執(zhí)行) */
//創(chuàng)建信號(hào)量,value表示初始信號(hào)總量,支持多少個(gè)操作來執(zhí)行
dispatch_semaphore_t t = dispatch_semaphore_create(1);
//發(fā)送一個(gè)信號(hào),讓信號(hào)總量+1
dispatch_semaphore_signal(t);
//使信號(hào)總量-1,如果總量為0,則會(huì)一直等待(阻塞所在線程),直到總量大于0則繼續(xù)執(zhí)行
dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER);
/*1.可以將異步執(zhí)行變?yōu)橥綀?zhí)行,如需要等待下載完后再直接返回?cái)?shù)據(jù)(我們也可以通過block回調(diào))*/
//總信號(hào)量設(shè)置為0
dispatch_semaphore_t t1 = dispatch_semaphore_create(0);
//執(zhí)行耗時(shí)代碼
void (^downloadTask)(void) = ^ {
//下載圖片
...
...
//完成后發(fā)送信號(hào)量
dispatch_semaphore_signal(t1);
};
downloadTask();
//一直等到信號(hào)量計(jì)數(shù)為1才執(zhí)行下一步,也就是等到圖片下載完后
dispatch_semaphore_wait(t1, DISPATCH_TIME_FOREVER);
/*2.保證線程安全*/
//設(shè)置信號(hào)量初始計(jì)數(shù)為1,保證只能有一個(gè)操作能進(jìn)來
dispatch_semaphore_t t2 = dispatch_semaphore_create(1);
//相當(dāng)于加鎖,消耗使用計(jì)數(shù),如果已經(jīng)被一個(gè)線程使用,后續(xù)只能掛起等待信號(hào)量回復(fù)
dispatch_semaphore_wait(t2, DISPATCH_TIME_FOREVER);
//執(zhí)行業(yè)務(wù)代碼
...
...
//解鎖
dispatch_semaphore_signal(t2);
/*3.模擬NSOperationQueue的最大并發(fā)操作數(shù)*/
//最大并發(fā)操作支持10
dispatch_semaphore_t t3 = dispatch_semaphore_create(10);
//剩余操作同上,其實(shí)就是類似于將NSOperationQueue的maxConcurrentOperationCount設(shè)置為10
復(fù)制代碼
- 后臺(tái)運(yùn)行
在App程序進(jìn)入后臺(tái)時(shí),我們應(yīng)該盡量釋放內(nèi)存和保存用戶數(shù)據(jù)或者狀態(tài)信息。在默認(rèn)情況下,應(yīng)該僅在5秒鐘處理這些工作,我們可以通過UIApplication的beginBackgroundTaskWithExpirationHandler方法來申請(qǐng)延長(zhǎng)處理時(shí)間,最多有十分鐘。
- (void)applicationDidEnterBackground:(UIApplication *)application {
//聲明關(guān)閉后臺(tái)任務(wù)代碼塊
void (^endBackgroundTask)(UIBackgroundTaskIdentifier backgroudTask) = ^(UIBackgroundTaskIdentifier backgroudTask) {
[[UIApplication sharedApplication] endBackgroundTask:backgroudTask];
backgroudTask = UIBackgroundTaskInvalid;
};
//開啟后臺(tái)任務(wù)
__block UIBackgroundTaskIdentifier backgroudTask;
backgroudTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
//十分鐘內(nèi)仍然沒有完成,系統(tǒng)處理終止句柄
endBackgroundTask(backgroudTask);
}];
//執(zhí)行相關(guān)代碼
//結(jié)束后臺(tái)任務(wù)
endBackgroundTask(backgroudTask);
}
復(fù)制代碼
- 線程死鎖
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@", [NSThread currentThread]);
});
}
復(fù)制代碼
在主隊(duì)列中增加同步代碼塊,就會(huì)造成死鎖,由于同步是需要立即順序執(zhí)行的,上述代碼中,Block中的方法需要在viewDidLoad結(jié)束后才能完成,但是viewDidLoad想要結(jié)束又必須先結(jié)束Block中的方法,所以相互永久等待,造成了死鎖。
GCD會(huì)造成循環(huán)引用嗎?
直接使用GCD的相關(guān)API一般是不會(huì)的,block結(jié)束后沒有循環(huán)引用的條件,YYKit的issues下有個(gè)有去的討論:dispatch_async的block里面需要_weak self嗎?
- 注意
- 同步執(zhí)行會(huì)在當(dāng)前線程執(zhí)行任務(wù),不具有開辟線程的能力或者說沒有必要開辟新的線程。并且,同步執(zhí)行必須等到Block函數(shù)執(zhí)行完畢,dispatch函數(shù)才會(huì)返回,從而阻塞同一串行隊(duì)列中外部方法的執(zhí)行。
- 異步執(zhí)行dispatch函數(shù)會(huì)直接返回,只有異步執(zhí)行才有開辟新線程的必要,但是異步執(zhí)行不一定會(huì)開辟新線程。
- 想要開辟新線程必須讓任務(wù)在異步執(zhí)行,想要開辟多個(gè)線程,只有讓任務(wù)在并行隊(duì)列中異步執(zhí)行才可以。執(zhí)行方式和隊(duì)列類型多層組合在一定程度上能夠?qū)崿F(xiàn)對(duì)于代碼執(zhí)行順序的調(diào)度。
- 同步+串行:未開辟新線程,串行執(zhí)行任務(wù);同步+并行:未開辟新線程,串行執(zhí)行任務(wù);異步+串行:新開辟一條線程,串行執(zhí)行任務(wù);異步+并行:開辟多條新線程,并行執(zhí)行任務(wù);在主線程中同步使用主隊(duì)列執(zhí)行任務(wù),會(huì)造成死鎖。
線程安全
線程安全主要是由于系統(tǒng)的線程調(diào)度具有一定的隨機(jī)性造成的,由于是多并發(fā),多個(gè)線程同時(shí)對(duì)一份數(shù)據(jù)進(jìn)行讀寫,就可能在讀取執(zhí)行一般的時(shí)候另外一個(gè)線程去寫入,導(dǎo)致數(shù)據(jù)異常。線程安全即保證線程同步
- 線程安全的類的特征
- 該類的對(duì)象可以被多個(gè)線程安全訪問。
- 每個(gè)線程調(diào)用對(duì)象的任意方法都會(huì)得到正確的結(jié)果。
- 每個(gè)線程調(diào)用對(duì)象的任意方法之后,該對(duì)象仍保持合理狀態(tài)。
- @synchronized是對(duì)mutex遞歸鎖的封裝
為了解決這個(gè)問題,Objective-C的多線程支持引入同步,使@synchronized修飾代碼塊,被修飾的代碼塊可簡(jiǎn)稱為同步代碼塊,語法格式如下
@synchronized (obj) {
//同步代碼塊
}
復(fù)制代碼
其中obj就是同步監(jiān)視器,當(dāng)一個(gè)線程執(zhí)行同步前,必須先獲得同步監(jiān)視器的鎖定,任何時(shí)刻只能有一個(gè)線程獲得鎖定,執(zhí)行完成后,才會(huì)釋放,如果此時(shí)有新的線程訪問,那么新線程會(huì)進(jìn)入休眠狀態(tài)。通常推薦使用可能被并發(fā)訪問的共享資源作為同步監(jiān)視器。
iOS中的鎖
1. OSSpinLock(自旋鎖)
- 等待鎖的線程處于忙等(busy-wait)狀態(tài),一直占用著CPU資源;
- 目前已經(jīng)不再安全,可能會(huì)出現(xiàn)優(yōu)先級(jí)翻轉(zhuǎn)問題;
- 如果等待鎖的線程優(yōu)先級(jí)較高,它會(huì)一直占用著CPU資源,優(yōu)先級(jí)低的線程就無法釋放鎖;
- 需要導(dǎo)入頭文件
#import <libkern/OSatomic.h>
//初始化
OSSpinLock lock = OS_SPINLOCK_INIT;
//嘗試加鎖(如果需要等待就不加鎖,直接返回false;如果不需要等待加鎖,返回true)
bool resule = OSSpinLockTry(&lock);
//加鎖
OSSpinLock(&lock);
//解鎖
OSSpinLockUnlock(&lock);
復(fù)制代碼
2. os_unfair_lock
- 用于取代不安全的OSSpinLock,從iOS10開始支持;
- 從底層調(diào)用看,等待os_unfair_locks鎖的線程會(huì)處于休眠狀態(tài),并非忙等;
- 需要導(dǎo)入頭文件
#import <os/lock.h>
//初始化
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
//嘗試加鎖
os_unfair_lock_trylock(&lock);
//加鎖
os_unfair_lock_lock(&lock);
//解鎖
os_unfair_lock_unlock(&lock);
復(fù)制代碼
3. pthread_mutex
互斥鎖
- mutex叫做“互斥鎖”,等待的線程會(huì)處于休眠狀態(tài)
- 需要導(dǎo)入頭文件
#import <pthread.h>
//初始化鎖的屬性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NORMAL);
//初始化
pthread_mutex_t mutex;
pthread_mutex_init (&mutex,&attr);
//嘗試加鎖
pthread_mutex_trylock (&mutex);
//加鎖
pthread_mutex_lock (&mutex);
//解鎖
pthread_mutex_unlock (&mutex);
//銷毀相關(guān)資源
pthread_mutexattr_unlock(&attr);
pthread_mutex_destroy(&mutex);
復(fù)制代碼
遞歸鎖
- 遞歸鎖:允許同一個(gè)線程對(duì)一把鎖進(jìn)行重復(fù)加鎖
// 初始化屬性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
// 初始化鎖
pthread_mutex_t mutex;
pthread_mutex_init(mutex, &attr);
// 銷毀屬性
pthread_mutexattr_destroy(&attr);
復(fù)制代碼
條件
// 初始化鎖
pthread_mutex_t mutex;
//NULL代表使用默認(rèn)屬性
pthread_mutex_init(&mutex, NULL);
// 初始化條件
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
//等待條件(進(jìn)入休眠,放開mutex鎖;被喚醒后,會(huì)再次對(duì)mutex加鎖)
pthread_cond_wait(&cond, &mutex);
//激活一個(gè)等待條件的線程
pthread_cond_signal(&cond);
//銷毀資源
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
復(fù)制代碼
4. NSLock、NSRecursiveLock
- NSLock是對(duì)mutex普通鎖的封裝
@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
@interface NSLock : NSObject <NSLocking>
{
- (BOOL)tryLock;
- (BOOl)lockBeforeDate:(NSDate *)limit;
}
@end
//初始化鎖
NSLock *lock = [[NSLock alloc] init];
復(fù)制代碼
- NSRecursiveLock也是對(duì)mutex遞歸所得封裝,API跟NSLock基本一致。
5. NSCondition
- NScondition 是對(duì)mutex和cond的封裝
@interface NSCondition : NSObject <NSLocking>
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;
復(fù)制代碼
6. NSConditionLock
- NSConditionLock是對(duì)NSCondition的進(jìn)一步封裝,可以設(shè)置具體的條件值
@interface NSConditionLock : NSObject <NSLocking> {
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
}
@end
復(fù)制代碼
7. dispatch_semaphore
- semaphore叫做信號(hào)量;
- 信號(hào)量的初始值,可以用來控制線程并發(fā)訪問的最大數(shù)量;
- 信號(hào)量的初始值為1,代表同時(shí)只允許1條線程訪問資源,保證線程同步
//信號(hào)量的初始值
int value = 1;
//初始化信號(hào)量
dispatch_semaphore semephore = dispatch_semaphore_creat(value);
//如果信號(hào)量的值<=0,當(dāng)前線程就會(huì)進(jìn)入休眠等待(直到信號(hào)量的值>0)
//如果信號(hào)量的值>0, 就減1,然后往下執(zhí)行后面的代碼
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//讓信號(hào)量的值加1
dispatch_semaphore_signal(semaphore);
復(fù)制代碼
8. dispatch_queue
- 直接使用GCD的串行隊(duì)列,也是可以實(shí)現(xiàn)線程同步的
dispatch_queue_t queue = dispatch_queue_creat("lock_queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
//任務(wù)
})