多线程中的加锁之自旋锁

https://www.jianshu.com/p/bef75ad8a67d
这篇文章简述了多线程存在的安全隐患,本篇文章解决多线程存在的安全隐患。
要想解决多个线程同时访问一个数据存在的安全隐患问题就要在每个线程访问这个数据的时候进行加锁,本篇文章介绍的是自旋锁。

OSSpinLock(自旋锁)

OC中提供的一个自旋锁是OSSpinLock。那么什么是自旋锁呢?我们先说一个锁,当一个线程在访问一个数据的时候,此时对该数据进行加锁,那么别的线程就无法再访问该数据,只有当前访问数据的线程能够对该数据进行访问。
那么锁是如何办到让其他线程无法访问某个数据呢?一种方式是让其他线程睡眠,一种方式是让其他线程忙等(busy-wait)。那么什么又是忙等呢?忙等类似一个while循环,一直占用着CPU,无法往下进行(记住这一点,忙等虽然能实现锁的功能,但它也会带来其他问题,我们后面会说到)。
下面就用代码来解决卖票的问题。
先看一下未加锁的代码:

  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

self.tickets = 20;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
    for (NSInteger i = 0; i < 10; i ++) {
        [self sellTickets];
    }
});
dispatch_async(queue, ^{
    for (NSInteger i = 0; i < 10; i ++) {
        [self sellTickets];
    }
});
}

- (void)sellTickets{
self.tickets --;
NSLog(@"剩余票数:%lu===%@", self.tickets, [NSThread currentThread]);
}

最终打印的结果:

   5.自旋锁[44484:2970620] 剩余票数:2==={number = 3, name = (null)}

总票数一共有20张,两个线程分别卖了十张票,正确的结果是将所有的票都卖完了,可打印还有2张票,所以结果肯定是错了。下面使用OSSpinLock进行加锁。

  - (void)sellTickets{
// 加锁
OSSpinLockLock(&_ticketsLock);
self.tickets --;
NSLog(@"剩余票数:%lu===%@", self.tickets, [NSThread currentThread]);
// 解锁
OSSpinLockUnlock(&_ticketsLock);
}

加锁之后打印结果就完全正确了,解决了多线程的安全隐患问题。

自旋锁存在的问题

当多个线程有优先级的时候,那么自旋锁就会出现问题。如果一个优先级低的线程先去访问某个数据,此时使用自旋锁进行了加锁,然后一个优先级高的线程又去访问这个数据,那么优先级高的线程会一直占着CPU资源,优先级低的线程就无法释放锁。由于自旋锁本身存在的问题,所以苹果已经废弃了OSSpinLock。

你可能感兴趣的:(多线程中的加锁之自旋锁)