[iOS] OC中的锁

为了解决线程同步问题,需要使用线程锁

@synchronized. 加锁的对象需要是同一个对象
NSLock 对象锁。 多次lock死锁
NSRecursiveLock 递归锁。 场景限制
NSConditionLock 条件锁。
pthread_mutex (C语言)互斥锁 linux 底层
dispatch_semaphore (GCD)。 信号量
OSSpinLock (不建议使用)

性能对比图:


[iOS] OC中的锁_第1张图片
2208956-4a024a1c6c6214db.png

@synchronized 关键字加锁 互斥锁,性能较差不推荐使用

@synchronized(OC对象,一般使用self){
          需要加锁的代码
}
注意:
   a.加锁的代码尽量少
   b.添加的OC对象必须在多个线程中都是同一对象
   c.优点是不需要显示的创建锁对象,便可以实现锁的机制
   d.@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。

NSLock 互斥锁 不能多次调用lock方法,会造成死锁

_mutexLock = [ [NSLock alloc] init];

在需要加锁的地方
// 加锁
[_mutexLock lock];
操作代码
。。。。。
// 解锁
[_mutexLock unlock];

NSRecursiveLock 递归锁
在递归中使用NSLock 多次调用lock ,会阻塞线程
换成NSRecursiveLock 便可以轻松解决,不过使用场景比较局限。

_rsLock = [[NSRecursiveLock alloc] init];
同NSLock 加锁,解锁

NSConditionLock 条件锁

//主线程中
    NSConditionLock *theLock = [[NSConditionLock alloc] init];

    //线程1
    dispatch_async(self.concurrentQueue, ^{
        for (int i=0;i<=3;i++)
        {
            [theLock lock];
            NSLog(@"thread1:%d",i);
            sleep(1);
            [theLock unlockWithCondition:i];
        }
    });

    //线程2
    dispatch_async(self.concurrentQueue, ^{
        [theLock lockWhenCondition:2];
        NSLog(@"thread2");
        [theLock unlock];
    });

在线程1中的加锁使用了lock,是不需要条件的,所以顺利的就锁住了。
unlockWithCondition:在开锁的同时设置了一个整型的条件 2 。
线程2则需要一把被标识为2的钥匙,所以当线程1循环到 i = 2 时,线程2的任务才执行。

NSConditionLock也跟其它的锁一样,是需要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是可以随意组合的,当然这是与你的需求相关的。

pthread_mutex 互斥锁(引入头文件#import

__block pthread_mutex_t mutex;
  pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
      NSLog(@"任务1");
      sleep(2);
      pthread_mutex_unlock(&mutex);

pthread_mutex_destroy(&mutex);  //释放该锁的数据结构

dispatch_semaphore 信号量实现加锁(GCD 中提供的一种信号机制,但是有信号量与互斥锁是有区别的)

// 创建信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
         NSLog(@"任务1");
        sleep(10);
        dispatch_semaphore_signal(semaphore);
    });

OSSpinLock 效率最高,但是不推荐使用了已经

//创建锁
    _pinLock = OS_SPINLOCK_INIT;
            //加锁
            OSSpinLockLock(&_pinLock);
            //解锁
            OSSpinLockUnlock(&_pinLock);

总结

@synchronized:适用线程不多,任务量不大的多线程加锁
NSLock:其实NSLock并没有想象中的那么差,不知道大家为什么不推荐使用
dispatch_semaphore_t:使用信号来做加锁,性能提升显著
NSCondition:使用其做多线程之间的通信调用不是线程安全的
NSConditionLock:单纯加锁性能非常低,比NSLock低很多,但是可以用来做多线程处理不同任务的通信调用
NSRecursiveLock:递归锁的性能出奇的高,但是只能作为递归使用,所以限制了使用场景
NSDistributedLock:因为是MAC开发的,就不讨论了
POSIX(pthread_mutex):底层的api,复杂的多线程处理建议使用,并且可以封装自己的多线程
OSSpinLock:性能也非常高,可惜出现了线程问题
dispatch_barrier_async/dispatch_barrier_sync:测试中发现dispatch_barrier_sync比dispatch_barrier_async性能要高,真是大出意外

Q:自旋和互斥的对比
A:相同点:都可以解决线程同步问题
不同点:
互斥锁会在访问被加锁数据时,会休眠等待,当数据解锁,互斥锁会被唤醒。
自旋锁遇到被加锁数据时,会进入死循环等待,当数据解锁,自旋锁马上访问。
自旋锁比互斥锁效率高!
Q:以上锁注意事项
Q:用C/OC/C++,任选其一,实现自旋或互斥?

你可能感兴趣的:([iOS] OC中的锁)