本文通過信號量解決了 并發線程,耗時不同,順序結束 問題。
信號量(Semaphore),有時被稱為信號燈,是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被并發調用。在進入一個關鍵代碼段之前,線程必須獲取一個信號量;一旦該關鍵代碼段完成了,那么該線程必須釋放信號量。其它想進入該關鍵代碼段的線程必須等待直到第一個線程釋放信號量
一、API
1、創建信號量
value : 是一個不小于0的值,否則創建失敗
返回一個dispatch_semaphore_t類型的信號量。
dispatch_semaphore_t dispatch_semaphore_create(long value);
2、等待信號量
信號量-1操作
如果dsema信號量的值大于0,該函數所處線程就繼續執行下面的語句,并且將信號量的值減1;
如果desema的值為0,那么這個函數就阻塞當前線程等待timeout,如果等待期間desema的值被dispatch_semaphore_signal函數加1了,且該函數(即dispatch_semaphore_wait)所處線程獲得了信號量,那么就繼續向下執行并將信號量減1。如果等待期間沒有獲取到信號量或者信號量的值一直為0,那么等到timeout時,其所處線程自動執行其后語句。
dsema : 信號量
timeout :超時時間 可以使用DISPATCH_TIME_NOW or DISPATCH_TIME_FOREVER
返回值 : 成功返回0,如果timeout了返回非0。
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
3、釋放信號量
信號量+1操作
如果之前的值小于0,這個函數在返回之前喚醒了一個等待線程。
如果線程被喚醒,該函數將返回非0。否則返回0。
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
【重要】 dispatch_semaphore_signal與dispatch_semaphore_wait配對使用,dispatch_semaphore_wait先調用,等待信號量。執行完成之后釋放信號量。
二、應用
1、控制并發數,管理有限資源
線程并不是越多越好,還要考慮到線程資源競爭、內存、CPU等情況。 我們知道NSOperationQueue可以控制最大并發數,那么GCD可不可以呢?
答案是肯定的,使用信號量Dispatch Semaphore實現。
例:某個資源最多只允許6個線程同時訪問
//創建一個value為6的信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(6);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//模擬有20個任務 等待執行
for (int i = 0; i < 20; i++)
{
//等待一個信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(queue, ^{
NSLog(@"任務%d執行--currentThread%@",i,[NSThread currentThread]);
[NSThread sleepForTimeInterval:arc4random() % 60 / 10.0];
//執行完成之后釋放信號量
dispatch_semaphore_signal(semaphore);
});
}
【鎖】當信號量的值為1時,表示同時只有一個線程可以訪問資源,實現了一種鎖的效果
2、并發線程,耗時不同,順序結束
網上的實現方法,是每個執行完成后的任務,不斷循環判斷上一個任務的狀態。個人覺得不是很好。
現在通過信號量實現如下,
如果哪位大神發現有問題,歡迎批評指正。
【核心思想】利用 dsema 為0時dispatch_semaphore_wait會一直等待,直到dsema大于0,才會繼續執行wait以下的語句。
#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 {
//創建一個保存信號量的數組
//假設有100個任務,那么有99個任務需要等待上一個任務結束
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
控制臺
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