1,信号量
1.1,什么事信号量-dispatch_semaphore_t?
dispatch_semaphore_t dispatch_semaphore_create(long value);
关于这个函数,我们在官网,查看他的定义是什么?
参数:信号量的初始值,不要小于0
返回值:就是创建了一个信号量
1.2,讨论
Passing zero for the value is useful for when two threads need to reconcile
the completion of a particular event. Passing a value greater than zero is
useful for managing a finite pool of resources, where the pool size is equal
to the value.
翻译:
当两个线程需要协调特定事件的完成时,传递零是很有用的。
传递大于零的值对于管理有限的资源池非常有用,其中池大小等于该值。
1.3,注意点
Calls to dispatch_semaphore_signal must be balanced with calls to wait().
Attempting to dispose of a semaphore with a count lower than value
causes an EXC_BAD_INSTRUCTION exception.
翻译:
对dispatch_semaphore_signal的调用必须与对wait()的调用进行平衡。
试图以低于值的计数来处理信号量会导致EXC_BAD_INSTRUCTION异常。
也就是说 "dispatch_semaphore_signal" 和 "dispatch_semaphore_wait"必须一一匹配,
如果不匹配,就会报"EXC_BAD_INSTRUCTION"这个错误
1.4,使用
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_CONCURRENT);
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"当前 - %d, 线程 - %@", i, [NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
/**
* dispatch_semaphore_create(0)
* dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
* 答案:从0到9,按照顺序执行。因为需要等待一个信号回来,才执行下一个
*/
- 异步函数+并发队列+信号量(0)
- 从0到9,按照顺序执行。因为需要等待一个信号回来,才执行下一个
1.5,总结
-
应用场景:同步当锁, 控制GCD最大并发数
-
dispatch_semaphore_create():创建信号量
-
dispatch_semaphore_wait():等待信号量,信号量减1。当信号量< 0时会阻塞当前线程,根据传入的等待时间决定接下来的操作——如果永久等待将等到信号(signal)才执行下去
-
dispatch_semaphore_signal():释放信号量,信号量加1。当信号量>= 0 会执行wait之后的代码
面试题
1,异步函数+并发队列+信号量(1)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_CONCURRENT);
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"当前 - %d, 线程 - %@", i, [NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
-
dispatch_semaphore_create(1) & dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
-
从0到9乱序执行,有时顺序执行,有时乱序执行
-
因为控制信号量为1,又是异步函数,所以谁先发出signal信号不确定,造成有时顺序执行,有时乱序执行的情况
2,异步函数+并发队列+信号量(1)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_CONCURRENT);
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"当前 - %d, 线程 - %@", i, [NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW);
}
-
dispatch_semaphore_create(1) & dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)
-
从0到9乱序执行,因为不用一直等待信号发出才执行,又是异步函数,所以乱序执行
3,异步函数+串行队列+信号量(1)或 (0)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_SERIAL_INACTIVE);
NSLog(@"tt --- 1");
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
NSLog(@"tt --- 4");
dispatch_semaphore_signal(sem);
});
NSLog(@"tt --- 2");
dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW);
NSLog(@"tt --- 3");
-
异步函数+同步队列+信号量(1)或 (0)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)
-
答案:1,2,3,崩溃
-
因为是串行队列,加上信号量为1,相当于产生死锁
4,异步函数+串行队列+信号量(1)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_SERIAL_INACTIVE);
NSLog(@"tt --- 1");
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
NSLog(@"tt --- 4");
dispatch_semaphore_signal(sem);
});
NSLog(@"tt --- 2");
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"tt --- 3");
- 答案:1,2,3,崩溃
5,异步函数+串行队列+信号量(0)+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
dispatch_queue_t queue = dispatch_queue_create("CJL", DISPATCH_QUEUE_SERIAL_INACTIVE);
NSLog(@"tt --- 1");
//利用信号量来改写
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
NSLog(@"tt --- 4");
dispatch_semaphore_signal(sem);
});
NSLog(@"tt --- 2");
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"tt --- 3");
- 答案:1,2,阻塞
6,信号量(0)+ 主队列 + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER)
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
NSLog(@"dieLock2 ---- 1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"dieLock2 ---- 4");
dispatch_semaphore_signal(sem);
});
NSLog(@"dieLock2 ---- 2");
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"dieLock2 ---- 3");
/*
* 信号量为:dispatch_semaphore_create(0)
* dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
* 答案:1,2,等待
* 为0时,因为不允许信号通过,所以为1,2,永久等待信号,才去执行
*/
7,信号量(0)或 (1)+ 主队列 + dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
NSLog(@"dieLock2 ---- 1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"dieLock2 ---- 4");
dispatch_semaphore_signal(sem);
});
NSLog(@"dieLock2 ---- 2");
dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW);
NSLog(@"dieLock2 ---- 3");
- 答案:1,2,3,4
- 因为是DISPATCH_TIME_NOW,所以先于3先执行,在执行4
2,死锁
队列的相互等待会造成死锁
2.1,主线程+主队列
NSLog(@"dieLock4 --- 1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"dieLock4 --- 3");
});
NSLog(@"dieLock4 --- 2");
//答案:1,崩溃
2.2,异步函数嵌套同步函数 + 串行队列(即同步队列)
// 同步队列
dispatch_queue_t queue = dispatch_queue_create("com.CJL.Queue", NULL);
NSLog(@"dieLock3 --- 1");
// 异步函数
dispatch_async(queue, ^{
NSLog(@"dieLock3 --- 2");
// 同步函数
dispatch_sync(queue, ^{
NSLog(@"dieLock3 --- 3");
});
NSLog(@"dieLock3 --- 4");
});
NSLog(@"dieLock3 --- 5")
//答案:1,5,2,崩溃