浅谈iOS中的锁的介绍及使用

2020-01-21 02:17:48于海丽

2017-10-19 17:18:08.054304+0800 Thread-Lock[40056:946096] 线程2线程加锁
2017-10-19 17:18:10.056071+0800 Thread-Lock[40056:946099] 线程1线程唤醒
2017-10-19 17:18:10.056231+0800 Thread-Lock[40056:946099] 线程1线程解锁
2017-10-19 17:18:10.056244+0800 Thread-Lock[40056:946096] 线程2线程唤醒
2017-10-19 17:18:10.056445+0800 Thread-Lock[40056:946096] 线程2线程解锁

由以上内容总结:

    在加上锁之后,调用条件对象的 wait 或 waitUntilDate: 方法来阻塞线程,直到条件对象发出唤醒信号或者超时之后,再进行之后的操作。 signal 和 broadcast 方法的区别在于,signal 只是一个信号量,只能唤醒一个等待的线程,想唤醒多个就得多次调用,而 broadcast 可以唤醒所有在等待的线程。

3.dispatch_semaphore

dispatch_semaphore 使用信号量机制实现锁,等待信号和发送信号。

    dispatch_semaphore 是 GCD 用来同步的一种方式,与他相关的只有三个函数,一个是创建信号量,一个是等待信号,一个是发送信号。 dispatch_semaphore 的机制就是当有多个线程进行访问的时候,只要有一个获得了信号,其他线程的就必须等待该信号释放。

常用相关API:


dispatch_semaphore_create(long value);
dispatch_semaphore_wait(dispatch_semaphore_t _Nonnull dsema, dispatch_time_t timeout);
dispatch_semaphore_signal(dispatch_semaphore_t _Nonnull dsema);

用法:


- (void)viewDidLoad {
  [super viewDidLoad];

  [self dispatch_semaphore];
}

- (void)dispatch_semaphore {
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
  dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 6 * NSEC_PER_SEC);

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_semaphore_wait(semaphore, overTime);
    NSLog(@"线程1开始");
    sleep(5);
    NSLog(@"线程1结束");
    dispatch_semaphore_signal(semaphore);
  });
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);
    dispatch_semaphore_wait(semaphore, overTime);
    NSLog(@"线程2开始");
    dispatch_semaphore_signal(semaphore);
  });
}

控制台输出:

2017-10-19 18:30:37.672490+0800 Thread-Lock[40569:993613] 线程1开始
2017-10-19 18:30:42.673845+0800 Thread-Lock[40569:993613] 线程1结束
2017-10-19 18:30:42.674165+0800 Thread-Lock[40569:993612] 线程2开始

//如果 overTime 改成 3 秒

控制台输出:
2017-10-19 18:32:32.078186+0800 Thread-Lock[40634:995921] 线程1开始
2017-10-19 18:32:35.082943+0800 Thread-Lock[40634:995920] 线程2开始
2017-10-19 18:32:37.083115+0800 Thread-Lock[40634:995921] 线程1结束

由以上内容总结:

    dispatch_semaphore 和 NSCondition 类似,都是一种基于信号的同步方式,但 NSCondition 信号只能发送,不能保存(如果没有线程在等待,则发送的信号会失效)。而 dispatch_semaphore 能保存发送的信号。dispatch_semaphore 的核心是 dispatch_semaphore_t 类型的信号量。 dispatch_semaphore_create(1) 方法可以创建一个 dispatch_semaphore_t 类型的信号量,设定信号量的初始值为 1。注意,这里的传入的参数必须大于或等于 0,否则 dispatch_semaphore_create 会返回 NULL。 dispatch_semaphore_wait(semaphore, overTime); 方法会判断 semaphore 的信号值是否大于 0。大于 0 不会阻塞线程,消耗掉一个信号,执行后续任务。如果信号值为 0,该线程会和 NSCondition 一样直接进入 waiting 状态,等待其他线程发送信号唤醒线程去执行后续任务,或者当 overTime 时限到了,也会执行后续任务。 dispatch_semaphore_signal(semaphore); 发送信号,如果没有等待的线程接受信号,则使 signal 信号值加一(做到对信号的保存)。 一个 dispatch_semaphore_wait(semaphore, overTime); 方法会去对应一个 dispatch_semaphore_signal(semaphore); 看起来像 NSLock 的 lock 和 unlock,其实可以这样理解,区别只在于有信号量这个参数,lock unlock 只能同一时间,一个线程访问被保护的临界区,而如果 dispatch_semaphore 的信号量初始值为 x ,则可以有 x 个线程同时访问被保护的临界区。