iOS

iOS中的几种锁

2018-12-13  本文已影响10人  无敌大闸蟹

多个线程访问同一块资源的时候,很容易引发数据混乱问题 所以我们就需要给我们的任务加上锁 网上大多的例子都是卖票的

@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);
}

可以看到打印的

image.png
这里就是抢占了资源 当两个线程同时访问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];
    
}

NSRecursiveLockNSCondition 也是基于pthread_ mutex的封装 用法和NSLock一致 就不写了
NSConditionLock是对NSCondition的封装 可以设定锁和解锁时候的值
1、initWithCondition:初始化Condition,并且设置状态值
2、lockWhenCondition:(NSInteger)condition:当状态值为condition的时候加锁
3、unlockWithCondition:(NSInteger)condition当状态值为condition的时候解锁

dispatch_semaphoreGCD里面的信号量 主要是三个方法
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

上一篇下一篇

猜你喜欢

热点阅读