美文网首页
多线程-加锁

多线程-加锁

作者: ForstDragon | 来源:发表于2019-07-23 17:49 被阅读0次

    [大佬的理解各种锁]
    (https://juejin.im/post/5a0a92996fb9a0451f307479)

    自己总结的,要自己写呀,要不记不住啊..

    一份数据被多个线程引用就会出现安全隐患


    多线程操作.png 线程加锁后.png

    1,iOS中的线程同步方案,分为自旋锁和互斥锁

    1.1 OSSpinLock(自旋锁),

    等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
    目前已经不再安全,可能会出现优先级反转问题
    如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
    需要导入头文件#import <libkern/OSAtomic.h>

    //初始化
    OSSpinLock lock = OS_SPINLOCK_INIT;
    //尝试加锁,如果需要等待就不加锁,直接返回false,如果不需要等待加锁就返回true
    bool result = OSSpinLockTry(&lock);
    //加锁
    OSSpinLockLock(&lock);
    //解锁
    OSSpinLockUnLock(&lock);
    
    
    @property (nonatomic ,assign) OSSpinLock lock;
    
    -(void)viewDidLoad
    
    {
    
        [super viewDidLoad];
    
        self.lock = OS_SPIN_LOCK_INIT;
    
    }
    
    -(void)lockTest
    
    {
    
    //尝试加锁,解决优先级较高的线程先调用的问题,避免造成死锁
    
        if (OSSpinLockTry(&_lock)) {
    
        int oldticketsCount = self.ticketsCount ;
    
        sleep(.2);
    
        oldticketsCount--;
    
         self.ticketsCount =   oldticketsCount;
    
        //解锁
    
        OSSpinlockUnlock(_lock);        
    
    
         }
    
        //加锁
    
        OSSpinLockLock(&_lock)
    
        int oldticketsCount = self.ticketsCount ;
    
        sleep(.2);
    
        oldticketsCount--;
    
         self.ticketsCount =   oldticketsCount;
    
        //解锁
    
        OSSpinlockUnlock(_lock);        
    
    }
    
    

    1.2 os_unfair_lock

    os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持
    从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
    需要导入头文件#import <os/lock.h>

    //初始化
    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
    //尝试加锁
    os_unfair_lock_trylock(&lock);
    //加锁
    os_fair_lock_lock(&lock);
    //解锁
    os_fair_lock_unlock(&lock);
    
    

    1.3、pthread_mutex

    1.3.1 常规锁

    mutex叫做”互斥锁”,等待锁的线程会处于休眠状态
    需要导入头文件#import <pthread.h>

    //初始化锁的属性
    pthread_mutexattr_t attr; //创建属性
    pthread_mutexattr_init(&attr);//舒适化属性
    pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NOMAL);//设置属性类型
    //初始化锁
    pthread_metux_t mutex;
    pthread_mutex_init(&mutex,&attr);
    //尝试加锁
    pthread_mutex_trylock(&mutex);
    //加锁
    pthread_mutex_lock(&mutex);
    //解锁
    pthread_mutex_unlock(&mutex);
    //销毁资源
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mutex);
    
    //属性
    @property (nonatomic , assign) pthread_mutex_t mutex;
    
    -(void)viewDidLoad{
    
             //初始化属性
           // pthread_mutexattr_t   attr;//创建
           // pthread_mutexattr_init(&attr);//初始化
          //  pthread_mutexattr_settertype(&attr , PTHREAD_MUTEX_NORMAL); 
            
            //初始化互斥锁
            //    pthread_mutex_init(&_mutex , &attr);
    
           直接等同于
              pthread_mutex_init(&_mutex , NULL);
    
    }
    
    -(void)testMutex
    {
         //尝试加锁
            pthread_mutex_trylock(&mutex);
        //加锁
          pthread_mutex_lock(&mutex);
       //解锁
          pthread_mutex_unlock(&mutex);
    
    }
    
    -(void)dealloc
    {
     //销毁相关资源
     pthread_mutexattr_destory(&attr);
     pthread_mutex_destory(&mutex);       
    }
    

    1.3.2、递归锁

      //初始化属性
      pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    //初始化锁
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,&attr);
    
    //销毁资源
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mutex);
    

    1.3.2、条件锁

    //初始化锁
    pthread_mutex_t mutex;
    //MULL表示使用默认属性
    pthread_mutex_init(&mutex,NULL);
    //初始化条件
    pthread_cond_t condition;
    pthread_cond_init(&condition,NULL);
    //等待条件(进入休眠,放开mutex锁,被唤醒后,再次对mutex进行加锁)
    pthread_cond_wait(&condition,&mutex);
    
    //激活一个等待该条件的线程
    pthread_cond_signal(&condition,&mutex);
    
    //激活所有等待该条件的线程
    pthread_cond_broadcast(&condition);
    
    //销毁资源
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&condition);
    
    

    1.4、NSLock、NSRecursiveLock

    NSLock是对mutex普通锁的封装

    @interface NSLock : NSObject <NSLocking> {
    -(BOOL)tryLock;
    -(BOOL)lockBeforeDate:(NSDate *)limit;
    }
    @end
    @protocol NSLocking
    -(void)lock;
    -(void)unlock
    @end
    
    //初始化锁
    NSLock *lock = [[NSLock alloc]init];
    
    NSRecursiveLock也是对mutex递归锁的封装,API和NSLock基本一致
    
    

    1.5、NSCondition

    NSCondition 是对mutex和cond的封装

    @interface NSCondition : NSObject <NSLocking>{
    -(void)wait;
    -(BOOL)waitUntilDate:(NSDate *)limit;
    -(void)signal;
    -(void)broadcast;
    }
    

    1.6、NSConditionLock

    NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值,

    @interface NSConditionLock : NSObject <NSLocking>{
    
    @property(readonly) NSInteger condition;
    -(instancetype)initWithCondition:(NSInteger)condition;
    -(BOOL)tryLock;
    -(BOOL)tryLockWhenCondition:(NSInteger)condition;
    -(void)unlockWithCondition:(NSInteger)condition;
    -(BOOL)lockBeforeDate:(NSDate *)limit;
    -(BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
    @end
    }
    

    1.7、dispatch_semaphore

    semaphore叫做"信号量";
    信号量的初始值,可以用来控制线程并发访问的最大数量,
    信号量的初始值为1,代表同时只允许一条线程访问资源,保证线程同步

    //信号量的初始值
    int value = 1;
    //初始化信号量
    dispath_semaphore_t semaphore = dispatch_semaphore_create(value);
    //如果信号量的值<=0,当前线程就会进入休眠等待(直到信号量的值>0)
    //如果信号量>0,就减1,然后往下执行后面的代码
    dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
    //让信号量的值加一
    disparch_semaphore_signal(semaphore);
    
    

    1.8、dispatch_queue

    直接使用GCD的串行队列,也是可以实现线程同步的

    dispatch_queue_t queue = dispatch_queue_create("lock_queue",DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        //任务
    });
    

    1.9、@synchronized

    GNUstep是GNU计划的项目之一,它将Cocoa的OC库重新开源实现了一遍
    源码地址:http://www.gnustep.org/resources/downloads.php
    虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值

    @synchronized是对mutex递归锁的封装
    源码查看:objc4中的objc-sync.mm文件
    @synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作

    @synchronized(obj){
      //做任务
    }
    

    2、iOS线程同步方案性能比较

    性能从高到低排序
    os_unfair_lock
    OSSpinLock
    dispatch_semaphore
    pthread_mutex
    dispatch_queue(DISPATCH_QUEUE_SERIAL)
    NSLock
    NSCondition
    pthread_mutex(recursive)
    NSRecursiveLock
    NSConditionLock
    @synchronized

    3、自旋锁和互斥锁比较

    3.1、什么情况用自旋锁比较划算?

    预计线程等待锁的时间很短
    加锁的代码经常被调用,但竞争情况很少发生
    cpu资源不紧张,多核处理器的

    3.2、什么情况使用互斥锁比较划算?

    预计线程等待锁的时间长,单核处理器,临界区有IO操作,
    临界区代码复杂或者循环量大
    临界区竞争非常激烈

    相关文章

      网友评论

          本文标题:多线程-加锁

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