美文网首页iOS
iOS中的几种锁

iOS中的几种锁

作者: 无敌大闸蟹 | 来源:发表于2018-12-13 15:06 被阅读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

相关文章

  • iOS 中常见的几种锁-代码示例

    iOS 中常见的几种锁-代码示例 iOS 中常见的几种锁-代码示例

  • iOS中的几种锁

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

  • 线程锁

    iOS中有几种线程锁:@synchronized、NSLock以及NSRecursiveLock(递归锁)。本文用...

  • iOS各种锁简介(上)

    iOS各种锁简介(上) 本篇文章主要介绍iOS中几种不同的锁的实现方式,既然是简介,这里不会涉及到原理上面的东西,...

  • iOS 笔记 - 锁

    今天简单写一下iOS中相关锁的内容,下图来自不再安全的 OSSpinLock中几种常见的锁加解锁的时间。 废弃的O...

  • iOS-锁

    iOS开发中知道的哪些锁? 哪个性能最差? 锁是线程编程同步工具的基础。iOS开发中常用的锁有如下几种: @syn...

  • iOS开发中常用的锁

    锁是线程编程同步工具的基础,在iOS开发中常用的锁有以下几种: @synchronized NSLock 对象锁 ...

  • iOS几种锁

  • 对iOS中几种锁的理解

    概述: 在程序编程中,很多地方会涉及到多线程操作的编程。而在多线程中,就不得不说说其中"锁"的存在。多线程开发是为...

  • iOS中几种锁的简单介绍

    多线程编程可以充分利用多核CPU的性能,提供资源的利用率能够提高程序的运行效率,使程序响应更快。但同时也带来了一些...

网友评论

    本文标题:iOS中的几种锁

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