iOS-OC 关于信号量 dispatch_semaphore_
2020-05-21 本文已影响0人
洧中苇_4187
线程同步方案
一.说明
dispatch_semaphore_t dispatch_semaphore_create(long value);
关于这个函数 我先贴张图,方便说明问题
image.png
参数:
信号量的初始值不要传一个小于0
的值
返回值:
一个新创建的信号量
细节讨论:
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.
翻译:
当两个线程需要协调特定事件的完成时,传递零是很有用的。
传递大于零的值对于管理有限的资源池非常有用,其中池大小等于该值。
注意点
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> 它能够使异步线程的执行顺序按照想要的顺序执行,这个特性有点像dispatch_group_create, dispatch_group_notify
和栅栏函数dispatch_barrier_sync
2> 它还有一个应用场景 加锁,多条线程访问读写同一数据时,会出现数据错乱的情况,在写之前加一把🔐
代码简单,示例如下:
当把加解锁的代码注释时,三个任务顺序可能随机执行,并且是开启新的线程,因为是异步+并发;
当打开加解锁代码时,有开启新线程的能力,但它会按顺序执行.
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
dispatch_semaphore_t signalSema = dispatch_semaphore_create(0);
//异步并行-开启多条线程
// dispatch_queue_t myqueue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);//异步+串行,开启一条子线程,执行
dispatch_queue_t myqueue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);//异步+并发,开启多条线程
// dispatch_queue_t myqueue = dispatch_get_global_queue(0, 0);//异步+并发,开启多条线程
// dispatch_queue_t myqueue = dispatch_get_main_queue();//异步串行队列,主线程执行,一个个执行
// dispatch_semaphore_wait(signalSema, DISPATCH_TIME_FOREVER);
dispatch_async(myqueue, ^{
NSLog(@"任务1-%@",[NSThread currentThread]);
dispatch_semaphore_signal(signalSema);
});
dispatch_semaphore_wait(signalSema, DISPATCH_TIME_FOREVER);
dispatch_async(myqueue, ^{
NSLog(@"任务2-%@",[NSThread currentThread]);
dispatch_semaphore_signal(signalSema);
});
dispatch_semaphore_wait(signalSema, DISPATCH_TIME_FOREVER);
dispatch_async(myqueue, ^{
NSLog(@"任务3-%@",[NSThread currentThread]);
dispatch_semaphore_signal(signalSema);
});
NSLog(@"\n");
}
这个的应用,在MJExtension有详细使用,有兴趣的可自行查看
#ifndef MJ_LOCK
#define MJ_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#endif
#ifndef MJ_UNLOCK
#define MJ_UNLOCK(lock) dispatch_semaphore_signal(lock);
#endif
// 信号量
#define MJExtensionSemaphoreCreate \
static dispatch_semaphore_t signalSemaphore; \
static dispatch_once_t onceTokenSemaphore; \
dispatch_once(&onceTokenSemaphore, ^{ \
signalSemaphore = dispatch_semaphore_create(1); \
});
总结
1.当多条线程时,传入 0
比较合适dispatch_semaphore_create
,
2.dispatch_semaphore_signal
和 dispatch_semaphore_wait
必须一一对应,如果不对应会报错EXC_BAD_INSTRUCTION
.
-
dispatch_semaphore_signal
调用一次,信号量+1
,dispatch_semaphore_wait
调用一次,信号量-1
,当信号量<0
时,当前线程就会卡主,没法往下执行,直到dispatch_semaphore_signal
被调用,使得信号量+1
,才会继续往下执行.