美文网首页
[iOS] OC中的锁

[iOS] OC中的锁

作者: SmartGao | 来源:发表于2017-11-28 14:44 被阅读0次

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

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

性能对比图:


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 <pthread.h>)

__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中的锁

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

  • iOS开发之路---我的6月面试总结

    第一部分:基础知识 1.oc中的各种锁。为什么有效率高低之分? 锁是线程编程同步工具的基础。iOS开发中常用的锁有...

  • OC中的锁

    > 锁是什么 * 锁是一种同步机制,用于存在多线程环境中实施对资源的访问限制.可以理解成用于排出并发的一种策略. ...

  • OC底层原理 - 23 iOS中的锁

    引言 锁是开发中最常用的同步工具,通过锁来实现对临界资源的访问控制,从而使目标代码段同一时间只会被一个线程执行。这...

  • swift中互斥锁

    在swift中,互斥锁如何写oc中的互斥锁:@synchronized(self) { //需要执行的代码块 } ...

  • OC底层原理21-锁的原理

    iOS--OC底层原理文章汇总[/p/14911da92f74] 本文探索常用锁以及@synchronized底层...

  • OC中的线程锁

    下面是各种线程锁的效率,当然这个结果只能当做一个定性分析,根据实现原理的不用,这些形形色色的锁再不同场景下可以发挥...

  • iOS之从MRC到ARC内存管理详解

    概述 在iOS中开发中,我们或多或少都听说过内存管理。iOS的内存管理一般指的是OC对象的内存管理,因为OC对象分...

  • iOS 开发中,批量修改OC类文件前缀

    iOS 开发中,批量修改OC类文件前缀

  • iOS中关于HTML的常用技术

    iOS中关于HTML的常用技术 OC&&JS交互 OC调用JS OC可以直接通过webview的- (nullab...

网友评论

      本文标题:[iOS] OC中的锁

      本文链接:https://www.haomeiwen.com/subject/uqtebxtx.html