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_signaldispatch_semaphore_wait必须一一对应,如果不对应会报错EXC_BAD_INSTRUCTION.

  1. dispatch_semaphore_signal 调用一次,信号量+1, dispatch_semaphore_wait 调用一次,信号量-1,当信号量 <0时,当前线程就会卡主,没法往下执行,直到dispatch_semaphore_signal被调用,使得信号量+1,才会继续往下执行.
上一篇下一篇

猜你喜欢

热点阅读