本文通過(guò)信號(hào)量解決了 并發(fā)線程,耗時(shí)不同,順序結(jié)束 問(wèn)題。
信號(hào)量(Semaphore),有時(shí)被稱為信號(hào)燈,是在多線程環(huán)境下使用的一種設(shè)施,是可以用來(lái)保證兩個(gè)或多個(gè)關(guān)鍵代碼段不被并發(fā)調(diào)用。在進(jìn)入一個(gè)關(guān)鍵代碼段之前,線程必須獲取一個(gè)信號(hào)量;一旦該關(guān)鍵代碼段完成了,那么該線程必須釋放信號(hào)量。其它想進(jìn)入該關(guān)鍵代碼段的線程必須等待直到第一個(gè)線程釋放信號(hào)量
一、API
1、創(chuàng)建信號(hào)量
value : 是一個(gè)不小于0的值,否則創(chuàng)建失敗
返回一個(gè)dispatch_semaphore_t類型的信號(hào)量。
dispatch_semaphore_t dispatch_semaphore_create(long value);
2、等待信號(hào)量
信號(hào)量-1操作
如果dsema信號(hào)量的值大于0,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語(yǔ)句,并且將信號(hào)量的值減1;
如果desema的值為0,那么這個(gè)函數(shù)就阻塞當(dāng)前線程等待timeout,如果等待期間desema的值被dispatch_semaphore_signal函數(shù)加1了,且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號(hào)量,那么就繼續(xù)向下執(zhí)行并將信號(hào)量減1。如果等待期間沒(méi)有獲取到信號(hào)量或者信號(hào)量的值一直為0,那么等到timeout時(shí),其所處線程自動(dòng)執(zhí)行其后語(yǔ)句。
dsema : 信號(hào)量
timeout :超時(shí)時(shí)間 可以使用DISPATCH_TIME_NOW or DISPATCH_TIME_FOREVER
返回值 : 成功返回0,如果timeout了返回非0。
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
3、釋放信號(hào)量
信號(hào)量+1操作
如果之前的值小于0,這個(gè)函數(shù)在返回之前喚醒了一個(gè)等待線程。
如果線程被喚醒,該函數(shù)將返回非0。否則返回0。
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
【重要】 dispatch_semaphore_signal與dispatch_semaphore_wait配對(duì)使用,dispatch_semaphore_wait先調(diào)用,等待信號(hào)量。執(zhí)行完成之后釋放信號(hào)量。
二、應(yīng)用
1、控制并發(fā)數(shù),管理有限資源
線程并不是越多越好,還要考慮到線程資源競(jìng)爭(zhēng)、內(nèi)存、CPU等情況。 我們知道NSOperationQueue可以控制最大并發(fā)數(shù),那么GCD可不可以呢?
答案是肯定的,使用信號(hào)量Dispatch Semaphore實(shí)現(xiàn)。
例:某個(gè)資源最多只允許6個(gè)線程同時(shí)訪問(wèn)
//創(chuàng)建一個(gè)value為6的信號(hào)量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(6);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//模擬有20個(gè)任務(wù) 等待執(zhí)行
for (int i = 0; i < 20; i++)
{
//等待一個(gè)信號(hào)量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(queue, ^{
NSLog(@"任務(wù)%d執(zhí)行--currentThread%@",i,[NSThread currentThread]);
[NSThread sleepForTimeInterval:arc4random() % 60 / 10.0];
//執(zhí)行完成之后釋放信號(hào)量
dispatch_semaphore_signal(semaphore);
});
}
【鎖】當(dāng)信號(hào)量的值為1時(shí),表示同時(shí)只有一個(gè)線程可以訪問(wèn)資源,實(shí)現(xiàn)了一種鎖的效果
2、并發(fā)線程,耗時(shí)不同,順序結(jié)束
網(wǎng)上的實(shí)現(xiàn)方法,是每個(gè)執(zhí)行完成后的任務(wù),不斷循環(huán)判斷上一個(gè)任務(wù)的狀態(tài)。個(gè)人覺(jué)得不是很好。
現(xiàn)在通過(guò)信號(hào)量實(shí)現(xiàn)如下,
如果哪位大神發(fā)現(xiàn)有問(wèn)題,歡迎批評(píng)指正。
【核心思想】利用 dsema 為0時(shí)dispatch_semaphore_wait會(huì)一直等待,直到dsema大于0,才會(huì)繼續(xù)執(zhí)行wait以下的語(yǔ)句。
#import "Semaphore.h"
@interface WorkSigle: NSObject
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
- (void)wait;
- (void)signal;
@end
@implementation WorkSigle
- (instancetype)init
{
self = [super init];
if (self) {
self.semaphore = dispatch_semaphore_create(0);
}
return self;
}
- (void)wait {
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
};
- (void)signal {
dispatch_semaphore_signal(self.semaphore);
}
@end
@interface Semaphore ()
@end
@implementation Semaphore
- (void)viewDidLoad {
[super viewDidLoad];
[self worker];
return;
}
- (void)worker {
//創(chuàng)建一個(gè)保存信號(hào)量的數(shù)組
//假設(shè)有100個(gè)任務(wù),那么有99個(gè)任務(wù)需要等待上一個(gè)任務(wù)結(jié)束
NSMutableArray * array = [NSMutableArray array];
for (int i = 0; i < 99; i++)
{
[array addObject:[WorkSigle new]];
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++)
{
dispatch_async(queue, ^{
// do task
[NSThread sleepForTimeInterval:arc4random() % 60 / 10.0];
NSLog(@"do task %i",i);
//wait a before task end
if (i == 0) {
//no before task
} else {
[array[i-1] wait];
}
//tell next task i'm end
if (i == 100-1) {
//no next
//call back
NSLog(@"call back %i",i);
} else {
[array[i] signal];
//call back
NSLog(@"call back %i",i);
}
});
}
}
@end
控制臺(tái)
2017-11-13 15:21:48.072591+0800 GCD[17635:828539] do task 34
2017-11-13 15:21:48.075363+0800 GCD[17635:828550] do task 45
2017-11-13 15:21:48.281590+0800 GCD[17635:828562] do task 56
2017-11-13 15:21:48.473248+0800 GCD[17635:828519] do task 13
2017-11-13 15:21:48.572649+0800 GCD[17635:828513] do task 8
2017-11-13 15:21:48.582305+0800 GCD[17635:828564] do task 59
2017-11-13 15:21:48.668709+0800 GCD[17635:828515] do task 10
2017-11-13 15:21:48.679914+0800 GCD[17635:828553] do task 48
2017-11-13 15:21:48.776232+0800 GCD[17635:828541] do task 36
2017-11-13 15:21:48.872509+0800 GCD[17635:828538] do task 33
2017-11-13 15:21:48.970302+0800 GCD[17635:828525] do task 19
2017-11-13 15:21:49.078067+0800 GCD[17635:828551] do task 46
2017-11-13 15:21:49.167016+0800 GCD[17635:828497] do task 3
2017-11-13 15:21:49.182590+0800 GCD[17635:828563] do task 58
2017-11-13 15:21:49.281073+0800 GCD[17635:828561] do task 55
2017-11-13 15:21:49.372164+0800 GCD[17635:828521] do task 14
2017-11-13 15:21:49.378074+0800 GCD[17635:828545] do task 40
2017-11-13 15:21:49.580778+0800 GCD[17635:828560] do task 54
2017-11-13 15:21:49.669122+0800 GCD[17635:828517] do task 12
2017-11-13 15:21:49.781760+0800 GCD[17635:828566] do task 61
2017-11-13 15:21:49.781760+0800 GCD[17635:828555] do task 50
2017-11-13 15:21:49.871966+0800 GCD[17635:828530] do task 26
2017-11-13 15:21:49.970870+0800 GCD[17635:828504] do task 1
2017-11-13 15:21:50.269989+0800 GCD[17635:828510] do task 5
2017-11-13 15:21:50.274258+0800 GCD[17635:828522] do task 18
2017-11-13 15:21:50.471128+0800 GCD[17635:828511] do task 6
2017-11-13 15:21:50.475007+0800 GCD[17635:828535] do task 30
2017-11-13 15:21:50.574400+0800 GCD[17635:828529] do task 24
2017-11-13 15:21:50.574376+0800 GCD[17635:828528] do task 23
2017-11-13 15:21:50.579521+0800 GCD[17635:828556] do task 52
2017-11-13 15:21:50.778321+0800 GCD[17635:828542] do task 37
2017-11-13 15:21:50.981140+0800 GCD[17635:828557] do task 51
2017-11-13 15:21:51.075328+0800 GCD[17635:828540] do task 35
2017-11-13 15:21:51.078376+0800 GCD[17635:828546] do task 41
2017-11-13 15:21:51.273801+0800 GCD[17635:828524] do task 21
2017-11-13 15:21:51.275046+0800 GCD[17635:828543] do task 38
2017-11-13 15:21:51.280770+0800 GCD[17635:828554] do task 49
2017-11-13 15:21:51.573139+0800 GCD[17635:828527] do task 22
2017-11-13 15:21:51.576009+0800 GCD[17635:828536] do task 31
2017-11-13 15:21:51.583474+0800 GCD[17635:828565] do task 60
2017-11-13 15:21:51.772837+0800 GCD[17635:828526] do task 20
2017-11-13 15:21:51.972211+0800 GCD[17635:828512] do task 7
2017-11-13 15:21:51.975443+0800 GCD[17635:828544] do task 39
2017-11-13 15:21:51.979601+0800 GCD[17635:828547] do task 42
2017-11-13 15:21:52.075513+0800 GCD[17635:828534] do task 29
2017-11-13 15:21:52.075513+0800 GCD[17635:828537] do task 32
2017-11-13 15:21:52.172614+0800 GCD[17635:828516] do task 11
2017-11-13 15:21:52.571668+0800 GCD[17635:828499] do task 2
2017-11-13 15:21:52.578809+0800 GCD[17635:828548] do task 43
2017-11-13 15:21:52.670324+0800 GCD[17635:828498] do task 4
2017-11-13 15:21:52.673575+0800 GCD[17635:828523] do task 17
2017-11-13 15:21:52.679255+0800 GCD[17635:828549] do task 44
2017-11-13 15:21:52.982977+0800 GCD[17635:828559] do task 57
2017-11-13 15:21:53.074717+0800 GCD[17635:828533] do task 28
2017-11-13 15:21:53.083673+0800 GCD[17635:828568] do task 63
2017-11-13 15:21:53.269872+0800 GCD[17635:828514] do task 9
2017-11-13 15:21:53.370297+0800 GCD[17635:828500] do task 0
2017-11-13 15:21:53.370498+0800 GCD[17635:828500] call back 0
2017-11-13 15:21:53.370511+0800 GCD[17635:828504] call back 1
2017-11-13 15:21:53.370527+0800 GCD[17635:828499] call back 2
2017-11-13 15:21:53.370531+0800 GCD[17635:828497] call back 3
2017-11-13 15:21:53.370540+0800 GCD[17635:828498] call back 4
2017-11-13 15:21:53.370545+0800 GCD[17635:828510] call back 5
2017-11-13 15:21:53.370553+0800 GCD[17635:828511] call back 6
2017-11-13 15:21:53.370567+0800 GCD[17635:828512] call back 7
2017-11-13 15:21:53.370572+0800 GCD[17635:828513] call back 8
2017-11-13 15:21:53.370579+0800 GCD[17635:828514] call back 9
2017-11-13 15:21:53.370587+0800 GCD[17635:828515] call back 10
2017-11-13 15:21:53.370593+0800 GCD[17635:828516] call back 11
2017-11-13 15:21:53.370600+0800 GCD[17635:828517] call back 12
2017-11-13 15:21:53.370608+0800 GCD[17635:828519] call back 13
2017-11-13 15:21:53.370615+0800 GCD[17635:828521] call back 14
2017-11-13 15:21:53.372781+0800 GCD[17635:828520] do task 15
2017-11-13 15:21:53.372895+0800 GCD[17635:828532] do task 27
2017-11-13 15:21:53.373570+0800 GCD[17635:828520] call back 15
2017-11-13 15:21:53.379881+0800 GCD[17635:828552] do task 47
2017-11-13 15:21:53.379918+0800 GCD[17635:828567] do task 62
2017-11-13 15:21:53.780496+0800 GCD[17635:828558] do task 53
2017-11-13 15:21:53.873460+0800 GCD[17635:828510] do task 69
2017-11-13 15:21:53.873460+0800 GCD[17635:828518] do task 16
2017-11-13 15:21:53.873654+0800 GCD[17635:828518] call back 16
2017-11-13 15:21:53.873661+0800 GCD[17635:828523] call back 17
2017-11-13 15:21:53.873674+0800 GCD[17635:828522] call back 18
2017-11-13 15:21:53.873680+0800 GCD[17635:828525] call back 19
2017-11-13 15:21:53.873686+0800 GCD[17635:828526] call back 20
2017-11-13 15:21:53.873692+0800 GCD[17635:828524] call back 21
2017-11-13 15:21:53.873697+0800 GCD[17635:828527] call back 22
2017-11-13 15:21:53.873708+0800 GCD[17635:828528] call back 23
2017-11-13 15:21:53.873712+0800 GCD[17635:828529] call back 24
2017-11-13 15:21:53.975420+0800 GCD[17635:828531] do task 25
2017-11-13 15:21:53.975593+0800 GCD[17635:828531] call back 25
2017-11-13 15:21:53.975603+0800 GCD[17635:828530] call back 26
2017-11-13 15:21:53.975610+0800 GCD[17635:828532] call back 27
2017-11-13 15:21:53.975618+0800 GCD[17635:828533] call back 28
2017-11-13 15:21:53.975623+0800 GCD[17635:828534] call back 29
2017-11-13 15:21:53.975629+0800 GCD[17635:828535] call back 30
2017-11-13 15:21:53.975635+0800 GCD[17635:828536] call back 31
2017-11-13 15:21:53.975641+0800 GCD[17635:828537] call back 32
2017-11-13 15:21:53.975648+0800 GCD[17635:828538] call back 33
2017-11-13 15:21:53.975654+0800 GCD[17635:828539] call back 34
2017-11-13 15:21:53.975660+0800 GCD[17635:828540] call back 35
2017-11-13 15:21:53.975668+0800 GCD[17635:828541] call back 36
2017-11-13 15:21:53.975672+0800 GCD[17635:828542] call back 37
2017-11-13 15:21:53.975679+0800 GCD[17635:828543] call back 38
2017-11-13 15:21:53.975683+0800 GCD[17635:828544] call back 39
2017-11-13 15:21:53.975692+0800 GCD[17635:828545] call back 40
2017-11-13 15:21:53.975699+0800 GCD[17635:828546] call back 41
2017-11-13 15:21:53.975704+0800 GCD[17635:828547] call back 42
2017-11-13 15:21:53.975710+0800 GCD[17635:828548] call back 43
2017-11-13 15:21:53.975715+0800 GCD[17635:828549] call back 44
2017-11-13 15:21:53.975722+0800 GCD[17635:828550] call back 45
2017-11-13 15:21:53.975727+0800 GCD[17635:828551] call back 46
2017-11-13 15:21:53.975733+0800 GCD[17635:828552] call back 47
2017-11-13 15:21:53.975738+0800 GCD[17635:828553] call back 48
2017-11-13 15:21:53.975744+0800 GCD[17635:828554] call back 49
2017-11-13 15:21:53.975751+0800 GCD[17635:828555] call back 50
2017-11-13 15:21:53.975822+0800 GCD[17635:828557] call back 51
2017-11-13 15:21:53.975832+0800 GCD[17635:828556] call back 52
2017-11-13 15:21:53.975879+0800 GCD[17635:828558] call back 53
2017-11-13 15:21:53.975891+0800 GCD[17635:828560] call back 54
2017-11-13 15:21:53.975902+0800 GCD[17635:828561] call back 55
2017-11-13 15:21:53.975911+0800 GCD[17635:828562] call back 56
2017-11-13 15:21:53.975921+0800 GCD[17635:828559] call back 57
2017-11-13 15:21:53.975938+0800 GCD[17635:828563] call back 58
2017-11-13 15:21:53.975943+0800 GCD[17635:828564] call back 59
2017-11-13 15:21:53.975952+0800 GCD[17635:828565] call back 60
2017-11-13 15:21:53.975973+0800 GCD[17635:828566] call back 61
2017-11-13 15:21:53.975985+0800 GCD[17635:828567] call back 62
2017-11-13 15:21:53.975988+0800 GCD[17635:828568] call back 63
2017-11-13 15:21:53.976538+0800 GCD[17635:828516] do task 75
2017-11-13 15:21:54.176963+0800 GCD[17635:828515] do task 74
2017-11-13 15:21:54.284440+0800 GCD[17635:828520] do task 79
2017-11-13 15:21:54.377329+0800 GCD[17635:828521] do task 78
2017-11-13 15:21:54.574439+0800 GCD[17635:828517] do task 76
2017-11-13 15:21:54.880915+0800 GCD[17635:828537] do task 96
2017-11-13 15:21:54.980239+0800 GCD[17635:828539] do task 98
2017-11-13 15:21:54.980239+0800 GCD[17635:828531] do task 89
2017-11-13 15:21:55.175092+0800 GCD[17635:828511] do task 70
2017-11-13 15:21:55.375959+0800 GCD[17635:828519] do task 77
2017-11-13 15:21:55.578825+0800 GCD[17635:828522] do task 82
2017-11-13 15:21:55.581010+0800 GCD[17635:828540] do task 99
2017-11-13 15:21:55.876915+0800 GCD[17635:828529] do task 88
2017-11-13 15:21:55.980127+0800 GCD[17635:828538] do task 97
2017-11-13 15:21:56.078312+0800 GCD[17635:828528] do task 87
2017-11-13 15:21:56.172802+0800 GCD[17635:828513] do task 72
2017-11-13 15:21:56.280488+0800 GCD[17635:828533] do task 92
2017-11-13 15:21:56.381052+0800 GCD[17635:828530] do task 90
2017-11-13 15:21:56.381052+0800 GCD[17635:828534] do task 93
2017-11-13 15:21:56.675105+0800 GCD[17635:828497] do task 67
2017-11-13 15:21:56.675105+0800 GCD[17635:828498] do task 68
2017-11-13 15:21:57.076616+0800 GCD[17635:828526] do task 84
2017-11-13 15:21:57.575141+0800 GCD[17635:828504] do task 66
2017-11-13 15:21:57.877850+0800 GCD[17635:828518] do task 81
2017-11-13 15:21:57.981143+0800 GCD[17635:828532] do task 91
2017-11-13 15:21:58.173369+0800 GCD[17635:828499] do task 65
2017-11-13 15:21:58.178202+0800 GCD[17635:828523] do task 80
2017-11-13 15:21:58.180606+0800 GCD[17635:828535] do task 94
2017-11-13 15:21:58.274143+0800 GCD[17635:828500] do task 64
2017-11-13 15:21:58.274327+0800 GCD[17635:828500] call back 64
2017-11-13 15:21:58.274344+0800 GCD[17635:828499] call back 65
2017-11-13 15:21:58.274361+0800 GCD[17635:828504] call back 66
2017-11-13 15:21:58.274364+0800 GCD[17635:828497] call back 67
2017-11-13 15:21:58.274378+0800 GCD[17635:828498] call back 68
2017-11-13 15:21:58.274390+0800 GCD[17635:828510] call back 69
2017-11-13 15:21:58.274399+0800 GCD[17635:828511] call back 70
2017-11-13 15:21:58.278561+0800 GCD[17635:828527] do task 86
2017-11-13 15:21:58.376748+0800 GCD[17635:828524] do task 85
2017-11-13 15:21:58.575410+0800 GCD[17635:828514] do task 73
2017-11-13 15:21:58.972735+0800 GCD[17635:828512] do task 71
2017-11-13 15:21:58.972964+0800 GCD[17635:828512] call back 71
2017-11-13 15:21:58.972977+0800 GCD[17635:828513] call back 72
2017-11-13 15:21:58.972990+0800 GCD[17635:828514] call back 73
2017-11-13 15:21:58.972998+0800 GCD[17635:828515] call back 74
2017-11-13 15:21:58.973004+0800 GCD[17635:828516] call back 75
2017-11-13 15:21:58.973012+0800 GCD[17635:828517] call back 76
2017-11-13 15:21:58.973020+0800 GCD[17635:828519] call back 77
2017-11-13 15:21:58.973027+0800 GCD[17635:828521] call back 78
2017-11-13 15:21:58.973034+0800 GCD[17635:828520] call back 79
2017-11-13 15:21:58.973041+0800 GCD[17635:828523] call back 80
2017-11-13 15:21:58.973048+0800 GCD[17635:828518] call back 81
2017-11-13 15:21:58.973053+0800 GCD[17635:828522] call back 82
2017-11-13 15:21:59.078535+0800 GCD[17635:828525] do task 83
2017-11-13 15:21:59.078770+0800 GCD[17635:828525] call back 83
2017-11-13 15:21:59.078781+0800 GCD[17635:828526] call back 84
2017-11-13 15:21:59.078787+0800 GCD[17635:828524] call back 85
2017-11-13 15:21:59.078799+0800 GCD[17635:828527] call back 86
2017-11-13 15:21:59.078809+0800 GCD[17635:828528] call back 87
2017-11-13 15:21:59.078818+0800 GCD[17635:828529] call back 88
2017-11-13 15:21:59.078827+0800 GCD[17635:828531] call back 89
2017-11-13 15:21:59.078835+0800 GCD[17635:828530] call back 90
2017-11-13 15:21:59.078846+0800 GCD[17635:828532] call back 91
2017-11-13 15:21:59.078852+0800 GCD[17635:828533] call back 92
2017-11-13 15:21:59.078862+0800 GCD[17635:828534] call back 93
2017-11-13 15:21:59.078867+0800 GCD[17635:828535] call back 94
2017-11-13 15:21:59.280196+0800 GCD[17635:828536] do task 95
2017-11-13 15:21:59.280386+0800 GCD[17635:828536] call back 95
2017-11-13 15:21:59.280394+0800 GCD[17635:828537] call back 96
2017-11-13 15:21:59.280411+0800 GCD[17635:828538] call back 97
2017-11-13 15:21:59.280416+0800 GCD[17635:828539] call back 98
2017-11-13 15:21:59.280422+0800 GCD[17635:828540] call back 99