iOS中的几种锁
多个线程访问同一块资源的时候,很容易引发数据混乱问题 所以我们就需要给我们的任务加上锁 网上大多的例子都是卖票的
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
self.count --;
NSLog(@"%ld",(long)self.count);
}
可以看到打印的
这里就是抢占了资源 当两个线程同时访问count时都为96 这里就存在数据错误和线程安全的问题了
使用线程同步技术,按照预定的先后次序依次进行,常见的线程同步技术就是
加锁
锁分为互斥锁和自旋锁
大概的区别就是当B线程在访问加锁的内容时线程A也来访问的话
互斥锁:线程A会被阻塞 如果线程A运行在X处理器上的话 X会被加入等待队列 而X可以去处理其他的任务 等B访问完了之后A继续访问
自旋锁:自旋锁一直占用CPU,他在未获得锁的情况下,一直运行,所以占用着CPU,如果不能在很短的时间内获得锁 相当耗性能
所以对比下很容易得出结论 如果锁的任务不怎么耗时的话选择自旋锁 耗时的话选择互斥锁
然后说几种常用的锁
os_unfair_lock
os_unfair_lock是自旋锁
//初始化
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
//加锁
os_unfair_lock_lock(&lock);
//解锁
os_unfair_lock_unlock(&lock);
需要导入#import <os/lock.h>
代码如下
#import "ViewController.h"
#import <os/lock.h>
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, assign) os_unfair_lock lock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
self.lock = OS_UNFAIR_LOCK_INIT;
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
os_unfair_lock_lock(&_lock);
self.count --;
NSLog(@"%ld",(long)self.count);
os_unfair_lock_unlock(&_lock);
}
pthread_mutex
属于互斥锁
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
需要导入#import <pthread.h>
初始化锁是
pthread_mutex_init(mutex, &attr);
初始化锁结束以后,销毁属性
pthread_mutexattr_destroy(&attr)
加锁解锁销毁锁
pthread_mutex_lock(&_mutex);
pthread_mutex_unlock(&_mutex);
pthread_mutex_destroy(&_mutex);
代码真尼玛麻烦
#import <pthread.h>
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, assign) pthread_mutex_t lock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
pthread_mutex_init(&_lock, &attr);
pthread_mutexattr_destroy(&attr);
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
pthread_mutex_lock(&_lock);
self.count --;
NSLog(@"%ld",(long)self.count);
pthread_mutex_unlock(&_lock);
}
NSLock
是基于pthread的封装 用起来也是很方便 也是最常见的锁
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) NSLock *lock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
self.lock = [[NSLock alloc] init];
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
[self.lock lock];
self.count --;
NSLog(@"%ld",(long)self.count);
[self.lock unlock];
}
NSRecursiveLock
和NSCondition
也是基于pthread_ mutex的封装 用法和NSLock一致 就不写了
NSConditionLock
是对NSCondition的封装 可以设定锁和解锁时候的值
1、initWithCondition:初始化Condition,并且设置状态值
2、lockWhenCondition:(NSInteger)condition:当状态值为condition的时候加锁
3、unlockWithCondition:(NSInteger)condition当状态值为condition的时候解锁
dispatch_semaphore
GCD里面的信号量 主要是三个方法
dispatch_semaphore_create(1) 1代表最大并发量 如果信号量的值 > 0就让信号量的值减1,然后继续往下执行代码 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
dispatch_semaphore_wait 等待
dispatch_semaphore_signal 让信号量+1
代码如下
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
self.semaphore = dispatch_semaphore_create(1);
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
self.count --;
NSLog(@"%ld",(long)self.count);
dispatch_semaphore_signal(self.semaphore);
}
dispatch_queue
GCD里面的 这里我们可以用串行队列的形式
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
dispatch_queue_t queue = dispatch_queue_create("sold", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(queue, ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
});
}
}
- (void)soldTicket
{
self.count --;
NSLog(@"%ld",(long)self.count);
}
@synchronized
也是我们常见的锁
@interface ViewController ()
@property (nonatomic, assign) NSInteger count;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
}
}
- (void)soldTicket
{
@synchronized([self class]){
self.count --;
NSLog(@"%ld",(long)self.count);
}
}
dispatch_barrier_async
栏栅块 这个例子好像不太适合用这个·········
这样吧 强行栏栅块一波···
- (void)viewDidLoad {
[super viewDidLoad];
self.count = 100;
dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_barrier_async(queue, ^{
for (int j = 0; j < 10; j ++) {
[self soldTicket];
}
});
});
}
}
- (void)soldTicket
{
self.count --;
NSLog(@"%ld",(long)self.count);
}
后面贴上其他地方抄过来的性能对比 我也不知道真的还是假的
锁的性能比较
性能从高到低排序
os_unfair_lock
dispatch_semaphore
pthread_mutex
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock
NSCondition
pthread_mutex(recursive)
NSRecursiveLock
NSConditionLock
@synchronized