扬庆の博客

多线程-信号量Dispatch_Semaphore

字数统计: 833阅读时长: 3 min
2022/03/25 Share

信号量(Dispatch Semaphore)

GCD中信号量,指的是 Dispatch Semaphore ,是持有计数的信号

信号量提供了三个函数

应用

  • 保持线程同步,将异步任务转换为同步执行任务
  • 保证线程安全,为线程加锁

保持线程同步

异步任务转换为同步 执行任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
dispatch_semaphore_create:
创建一个 Semaphore 并初始化信号的总量。

dispatch_semaphore_signal:
发送一个信号,让信号总量 +1。

dispatch_semaphore_wait:
可以使总信号量减1, 当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。

代码:
-(void)dispatch_semaphore{
// 信号量(注意:初始化信号量为0)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

__block NSInteger number = 0;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
number = 100;
NSLog(@"%@",[NSThread currentThread]);
sleep(4); // 延迟4秒,再解锁方便查看打印, 确实是加锁阻塞了当前线程
dispatch_semaphore_signal(semaphore);// 解锁
});

// 加锁
NSLog(@"%@",[NSThread currentThread]);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"semaphore --- end number = %zd",number);
}

打印结果

dispatch_semphore

保证线程安全,为线程加锁

在线程安全中可以将dispatch_semaphore_wait 看作加锁, dispatch_semaphore_signal看作解锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

// 注意:初始化信号量为1
_semaphore = dispatch_semaphore_create(1);

for (NSInteger i = 0 ; i < 100; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self asyncTask];
});
}
}

-(void)asyncTask {

dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);

_count++;

sleep(1);

NSLog(@"执行任务:%zd",_count);

dispatch_semaphore_signal(_semaphore);
}

打印结果

dispatch_semaphore_addlock

原因:

在子线程中并发执行 asyncTask,那么第一个添加到并发队列的,会将信号量 -1,此时信号量等于0,可以执行接下来的任务。而并发队列中其他任务,由于此时信号量不等于0, 必须等当前正在执行的任务执行完毕后调用dispatch_semaphore_signal 将信号量加1,才可以继续执行接下来的任务,以此类推,从而达到线程加锁的目的。

再举一个例子:

多个任务1-10,等全部任务结束之后再往下执行其他任务 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//创建一个并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//开启的是10个异步的操作,通过信号量,让10个异步的最多1个m,剩下的同步等待
for (NSInteger i = 0; i < 10; i++) {
dispatch_async(queue, ^{
//当信号量为0时候,阻塞当前线程
NSLog(@"执行任务 %ld", i);
sleep(1);
NSLog(@"完成当前任务 %ld", i);
_count++;

//释放信号
if (_count == 10){
dispatch_semaphore_signal(semaphore);
}
});
}

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"end------");

NSLog(@"go on next...");

执行结果为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
执行任务 0
执行任务 2
执行任务 1
执行任务 5
执行任务 7
执行任务 6
执行任务 3
执行任务 4
执行任务 8
执行任务 9
完成当前任务 9
完成当前任务 2
完成当前任务 1
完成当前任务 3
完成当前任务 7
完成当前任务 5
完成当前任务 0
完成当前任务 4
完成当前任务 8
完成当前任务 6
end------
go on next...

总结;

信号量可以做:

  1. 异步队列顺序执行,不阻塞主线程。
  2. 异步无序执行,阻塞主线程,执行完全部任务之后再做后续任务。
CATALOG
  1. 1. 信号量(Dispatch Semaphore)
    1. 1.0.1. 应用
  2. 1.1. 保持线程同步
  3. 1.2. 保证线程安全,为线程加锁
    1. 1.2.1. 原因:
    2. 1.2.2. 再举一个例子:
  4. 1.3. 总结;