多线程方案各种锁记录

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

所在头文件:#import

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

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

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

使用需要导入头文件import

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
-(BOOL)tryLock;//尝试加锁
-(BOOL)lockBeforeDate:(NSDate*)limt//在一定时间内,如果锁还是在锁着,在时间内等着,要是在时间内锁开了,就加个锁,返回YES,过了时间就不等,返回NO
......
@end

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end

5. NSCondition

是对mutex和cond的封装

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

6. NSConditionLock

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

@interface NSConditionLock:NSObject
//初始化,传入锁的条件或者说起始标记
-(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];
    }
}

你可能感兴趣的:(多线程方案各种锁记录)