美文网首页
多线程方案各种锁记录

多线程方案各种锁记录

作者: 分流替躺欧阳克 | 来源:发表于2019-06-09 23:35 被阅读0次

    1. OSSpinLock :自旋锁,锁住时处于忙等状态(时刻检查是否解锁)

    所在头文件:#import <libkern/OSAtomic.h>

    _lock = OS_SPINLOCK_INIT;//初始化。这里初始化一次,不能放在加锁解锁的函数里
    //即使不在同一个方法,只要是锁是同一把,就能锁住锁里的代码,只有一块代码在执行
    OSSpinLockLock(&_lock);//加锁
    //OSSpinLockLockTry 尝试加锁,若是没有锁住,就加个锁。
    //要锁的代码
    OSSpinLockUnlock(&_lock);//解锁
    

    自旋锁原理,隔一会儿就去检查下锁有没有被放开。
    目前锁不安了,出现优先级反转的情况。在开启多个线程的情况下,因为时间片轮转调度算法,有些线程优先级比较高,有些比较低,低优先级的线程加了锁,然而有些线程优先级比较高,系统会优先分配给高优先级的线程,高优先级的线程一直被执行,但是代码被优先级的线程锁着,导致死锁。

    2. os_unfair_lock :锁住时线程处于休眠状态,互斥锁

    使用需要导入头文件import<os/lock.h>

    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;初始化
    os_fair_lock_trylock(&lock);//尝试加锁
    os_unfair_look_lock(&lock);//加锁
    os_unfair_lock_unlock(&lock);//解锁
    

    3. pthread_mutex

    互斥锁,等待的线程会处于休眠状态

    - (void)__initMutex:(pthread_mutex_t*)mutex{
        //静态初始化。声明时直接初始化
        //pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        //初始化属性
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
        //动态初始化,先声明,运行时再赋值。
        pthread_mutex_init(mutex, &attr);
        //销毁锁
        pthread_mutexattr_destroy(&attr);
    }
    pthread_mutex_lock(&_mutex);//加锁
    pthread_mutex_unlock(&_mutex);//解锁
    

    递归锁:在同一个线程可以重复加锁,加多少次,解多少次。

    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);//递归锁,解决循环加锁的问题
    

    pthread_cond_t条件

    pthread_cond_t cond;//声明
    pthread_cond_init(&_cond, NULL);//初始化
    

    假设:

    1. __remove函数在线程1,__add在线程2,两个线程同时执行,但是线程1的__remove函数先加上了锁,此后__add函数就得等线程1的锁放开才能执行。
    2. 线程1的remove函数执行,发现data里元素个数小于0, 调用pthread_cond_wait(&condition, &_mutex)这句代码,让当前线程处于睡觉的状态,并且放开锁。
    3. 此时线程2的锁检测到线程1的锁被放开了,就在线程2加上锁,给data添加数据,然后pthread_cond_signal(&condition)唤醒因condition条件没达到就睡眠的线程,然后解开锁。
    4. 随着锁解开,之前进入睡眠的线程1就给锁锁住,然移除数组里的元素,最后解开锁。
      注:pthread_cond_wait(&condition,&mutex)是唤醒所有因condition而等待的线程。
    - (void)__remove
    {
        pthread_mutex_lock(&_mutex);
        if (self.data.count == 0) {
            pthread_cond_wait(&_cond, &_mutex);
        }
        [self.data removeLastObject];
        pthread_mutex_unlock(&_mutex);
    }
    

    线程2代码

    - (void)__add
    {
        pthread_mutex_lock(&_mutex);
        [self.data addObject:@"Test"];
        pthread_cond_signal(&_cond);//唤醒上面在等待的s线程
        pthread_mutex_unlock(&_mutex);
    }
    

    4. NSLock、NSRecursiveLock

    NSLock是对mutex的封装,接口

    @interface NSLock:NSObject<NSLocking>
    -(BOOL)tryLock;//尝试加锁
    -(BOOL)lockBeforeDate:(NSDate*)limt//在一定时间内,如果锁还是在锁着,在时间内等着,要是在时间内锁开了,就加个锁,返回YES,过了时间就不等,返回NO
    ......
    @end
    
    @protocol NSLocking
    - (void)lock;
    - (void)unlock;
    @end
    

    5. NSCondition

    是对mutex和cond的封装

    @interface NSCondition:NSObject <NSLocking>
    - (void)wait;
    - (BOOL)waitUntilDate:(NSDate*)limit;
    - (void)signal;//唤醒
    - (void)broadcast;//唤醒所有等待线程
    

    6. NSConditionLock

    是对NSCondition的进一步封装,通过一个数字对锁做标记,只有数字相同才能加锁

    @interface NSConditionLock:NSObject<NSLocking>
    //初始化,传入锁的条件或者说起始标记
    -(instancetype)initWithCondition:(NSInterger)condition;
    //当锁的条件或标记是condition
    -(void)lockWhenCondition::(NSInterger)condition;
    -(BOOL)tyLock;
    -(BOOL)tyLockWhenCondition:(NSInteger)condition;
    //解锁,并修改锁的条件为condition
    -(BOOL)unlockWhenCondition::(NSInterger)condition;
    //一定时间内加锁
    -(BOOL)lockBeforeDate:(NSDate*)limit;
    //一定时间内达到条件加锁  
    -(BOOL)lockWhenCondition:(NSInteger)contion:(NSinteger)condition beforeDate:(NSDate*)limit;
    

    7. 使用串行队列实现锁

    self.moneyQueue=dispatch_queue_create("moneyQueue", DISPATCH_QUEUE_SERIAL);
    
    - (void)saveMoney
    {
        dispatch_async(self.moneyQueue, ^{
            [super saveMoney];
        });
    }
    
    - (void)drawMoney
    {
        dispatch_async(self.moneyQueue, ^{
            [super drawMoney];
        });
    }
    

    把存钱取钱加在同一个队列里,保证存取同时只能进行一个。

    8. dispatch_semaphore_t

    使用信号量来实现锁,信号量初始化为1,保证同时只能进行一个。

    self.semaphore = dispatch_semaphore_create(5);//初始化
    - (void)otherTest
    {
        for (int i=0; i<20; i++) {
            [[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]start];
        }
    }
    
    - (void)test{
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    
        sleep(1);
        NSLog(@"test- %@",[NSThread currentThread]);
    
        dispatch_semaphore_signal(self.semaphore);
    }
    

    9. @synchronized

    可以把任意对象当锁,使用最方便,但是性能最低,底层封装的最复杂,同时也支持递归加锁。

    - (void)drawMoney
    {
        @synchronized (self) {
          [super drawMoney];
        }
    }
    - (void)saveMoney
    {
        @synchronized (self) {
          [super saveMoney];
        }
    }
    
    - (void)otherTest{
    //只是为了说明可以递归加锁,这里会无限循环
        @synchronized ([self class]) {
            NSLog(@"123");
            [self otherTest];
        }
    }
    

    相关文章

      网友评论

          本文标题:多线程方案各种锁记录

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