本文通过信号量解决了 并发线程,耗时不同,顺序结束 问题。
信号量(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