美文网首页
多线程:线程同步方案 各种锁

多线程:线程同步方案 各种锁

作者: 东方诗空 | 来源:发表于2022-04-09 15:41 被阅读0次

    iOS中的线程同步方案

    • OSSpinLock
    • os_unfair_lock
    • pthread_mutex
    • dispatch_semaphore
    • dispatch_queue(DISPATCH_QUEUE_SERIAL)
    • NSLock
    • NSRecursiveLock
    • NSCondition
    • NSConditionLock
    • @synchronized

    自旋锁 OSSpinLock

    OSSpinLock叫做”自旋锁”,等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源

    • 目前已经不再安全,可能会出现优先级反转问题
    • 如果等待锁的线程优先级较高,它会一直占用着CPU资源优先级低的线程无法释放锁
      需要导入头文件#import <libkern/OSAtomic.h>
    image.png

    自旋锁 os_unfair_lock 安全的

    os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持
    从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
    需要导入头文件#import <os/lock.h>

    image.png
    #import "OSUnfairLockDemo.h"
    #import <os/lock.h>
    
    @interface OSUnfairLockDemo()
    // Low-level lock
    // ll lock
    // lll
    // Low-level lock的特点等不到锁就休眠
    @property (assign, nonatomic) os_unfair_lock moneyLock;
    @property (assign, nonatomic) os_unfair_lock ticketLock;
    @end
    
    @implementation OSUnfairLockDemo
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.moneyLock = OS_UNFAIR_LOCK_INIT;
            self.ticketLock = OS_UNFAIR_LOCK_INIT;
        }
        return self;
    }
    
    // 死锁:永远拿不到锁
    - (void)__saleTicket
    {
        os_unfair_lock_lock(&_ticketLock);
        
        [super __saleTicket];
        
        os_unfair_lock_unlock(&_ticketLock);
    }
    
    - (void)__saveMoney
    {
        os_unfair_lock_lock(&_moneyLock);
        
        [super __saveMoney];
        
        os_unfair_lock_unlock(&_moneyLock);
    }
    
    - (void)__drawMoney
    {
        os_unfair_lock_lock(&_moneyLock);
        
        [super __drawMoney];
        
        os_unfair_lock_unlock(&_moneyLock);
    }
    
    @end
    

    pthread_mutex

    互斥锁pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    递归锁pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

    mutex叫做”互斥锁”,等待锁的线程会处于休眠状态
    需要导入头文件#import <pthread.h>

    互斥锁

    image.png image.png

    递归锁

    递归锁:允许同一个线程对一把锁进行重复加锁


    image.png
    #import "MutexDemo.h"
    #import <pthread.h>
    
    @interface MutexDemo()
    @property (assign, nonatomic) pthread_mutex_t ticketMutex;
    @property (assign, nonatomic) pthread_mutex_t moneyMutex;
    @end
    
    @implementation MutexDemo
    
    - (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_mutexattr_t attr;
    //    pthread_mutexattr_init(&attr);
    //    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
        // 初始化锁
        pthread_mutex_init(mutex, NULL);
        // 销毁属性
    //    pthread_mutexattr_destroy(&attr);
    }
    
    - (instancetype)init
    {
        if (self = [super init]) {
            [self __initMutex:&_ticketMutex];
            [self __initMutex:&_moneyMutex];
        }
        return self;
    }
    
    // 死锁:永远拿不到锁
    - (void)__saleTicket
    {
        pthread_mutex_lock(&_ticketMutex);
        
        [super __saleTicket];
        
        pthread_mutex_unlock(&_ticketMutex);
    }
    
    - (void)__saveMoney
    {
        pthread_mutex_lock(&_moneyMutex);
        
        [super __saveMoney];
        
        pthread_mutex_unlock(&_moneyMutex);
    }
    
    - (void)__drawMoney
    {
        pthread_mutex_lock(&_moneyMutex);
        
        [super __drawMoney];
        
        pthread_mutex_unlock(&_moneyMutex);
    }
    
    - (void)dealloc
    {
        pthread_mutex_destroy(&_moneyMutex);
        pthread_mutex_destroy(&_ticketMutex);
    }
    
    @end
    
    

    条件锁,线程依赖

    @interface MutexDemo3()
    @property (assign, nonatomic) pthread_mutex_t mutex;
    @property (assign, nonatomic) pthread_cond_t cond;
    @property (strong, nonatomic) NSMutableArray *data;
    @end
    
    @implementation MutexDemo3
    
    - (instancetype)init
    {
        if (self = [super init]) {
            // 初始化属性
            pthread_mutexattr_t attr;
            pthread_mutexattr_init(&attr);
            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
            // 初始化锁
            pthread_mutex_init(&_mutex, &attr);
            // 销毁属性
            pthread_mutexattr_destroy(&attr);
            
            // 初始化条件
            pthread_cond_init(&_cond, NULL);
            
            self.data = [NSMutableArray array];
        }
        return self;
    }
    
    - (void)otherTest
    {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
        
        [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
    }
    
    // 生产者-消费者模式
    
    // 线程1
    // 删除数组中的元素
    - (void)__remove
    {
        pthread_mutex_lock(&_mutex);
        NSLog(@"__remove - begin");
        
        if (self.data.count == 0) {
            // 等待
            pthread_cond_wait(&_cond, &_mutex);
        }
        
        [self.data removeLastObject];
        NSLog(@"删除了元素");
        
        pthread_mutex_unlock(&_mutex);
    }
    
    // 线程2
    // 往数组中添加元素
    - (void)__add
    {
        pthread_mutex_lock(&_mutex);
        
        sleep(1);
        
        [self.data addObject:@"Test"];
        NSLog(@"添加了元素");
        
        // 信号
        pthread_cond_signal(&_cond);
        // 广播
    //    pthread_cond_broadcast(&_cond);
        
        pthread_mutex_unlock(&_mutex);
    }
    
    - (void)dealloc
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    
    @end
    
    

    dispatch_semaphore 信号量

    信号量

    控制最大并发数量

    semaphore叫做”信号量”
    信号量的初始值,可以用来控制线程并发访问的最大数量
    信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步

    image.png
    
    @interface SemaphoreDemo()
    @property (strong, nonatomic) dispatch_semaphore_t semaphore;
    @property (strong, nonatomic) dispatch_semaphore_t ticketSemaphore;
    @property (strong, nonatomic) dispatch_semaphore_t moneySemaphore;
    @end
    
    @implementation SemaphoreDemo
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.semaphore = dispatch_semaphore_create(5);
            self.ticketSemaphore = dispatch_semaphore_create(1);
            self.moneySemaphore = dispatch_semaphore_create(1);
        }
        return self;
    }
    
    - (void)__drawMoney
    {
        dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
        
        [super __drawMoney];
        
        dispatch_semaphore_signal(self.moneySemaphore);
    }
    
    - (void)__saveMoney
    {
        dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
        
        [super __saveMoney];
        
        dispatch_semaphore_signal(self.moneySemaphore);
    }
    
    - (void)__saleTicket
    {
        dispatch_semaphore_wait(self.ticketSemaphore, DISPATCH_TIME_FOREVER);
        
        [super __saleTicket];
        
        dispatch_semaphore_signal(self.ticketSemaphore);
    }
    
    - (void)otherTest
    {
        for (int i = 0; i < 20; i++) {
            [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
        }
    }
    
    // 线程10、7、6、9、8
    - (void)test
    {
        // 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
        // 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        
        sleep(2);
        NSLog(@"test - %@", [NSThread currentThread]);
        
        // 让信号量的值+1
        dispatch_semaphore_signal(self.semaphore);
    }
    
    @end
    
    

    dispatch_queue(DISPATCH_QUEUE_SERIAL) 串行队列

    线程同步,让线程有顺序的执行,所以串行队列也可以实现线程同步

    image.png
    @interface SerialQueueDemo()
    @property (strong, nonatomic) dispatch_queue_t ticketQueue;
    @property (strong, nonatomic) dispatch_queue_t moneyQueue;
    @end
    
    @implementation SerialQueueDemo
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.ticketQueue = dispatch_queue_create("ticketQueue", DISPATCH_QUEUE_SERIAL);
            self.moneyQueue = dispatch_queue_create("moneyQueue", DISPATCH_QUEUE_SERIAL);
        }
        return self;
    }
    
    - (void)__drawMoney
    {
        dispatch_sync(self.moneyQueue, ^{
            [super __drawMoney];
        });
    }
    
    - (void)__saveMoney
    {
        dispatch_sync(self.moneyQueue, ^{
            [super __saveMoney];
        });
    }
    
    - (void)__saleTicket
    {
        dispatch_sync(self.ticketQueue, ^{
            [super __saleTicket];
        });
    }
    
    @end
    
    

    NSLock

    NSLock是对mutex普通锁的封装

    #import "NSLockDemo.h"
    
    @interface NSLockDemo()
    @property (strong, nonatomic) NSLock *ticketLock;
    @property (strong, nonatomic) NSLock *moneyLock;
    @end
    
    @implementation NSLockDemo
    
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.ticketLock = [[NSLock alloc] init];
            self.moneyLock = [[NSLock alloc] init];
        }
        return self;
    }
    
    // 死锁:永远拿不到锁
    - (void)__saleTicket
    {
        [self.ticketLock lock];
        
        [super __saleTicket];
        
        [self.ticketLock unlock];
    }
    
    - (void)__saveMoney
    {
        [self.moneyLock lock];
        
        [super __saveMoney];
        
        [self.moneyLock unlock];
    }
    
    - (void)__drawMoney
    {
        [self.moneyLock lock];
        
        [super __drawMoney];
        
        [self.moneyLock unlock];
    }
    
    @end
    
    

    NSRecursiveLock 对mutex递归锁的封装

    NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致

    NSCondition 对条件锁的封装

    NSCondition是对mutex和cond的封装

    #import "NSConditionDemo.h"
    
    @interface NSConditionDemo()
    @property (strong, nonatomic) NSCondition *condition;
    @property (strong, nonatomic) NSMutableArray *data;
    @end
    
    @implementation NSConditionDemo
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.condition = [[NSCondition alloc] init];
            self.data = [NSMutableArray array];
        }
        return self;
    }
    
    - (void)otherTest
    {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
        
        [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
    }
    
    
    // 线程1
    // 删除数组中的元素
    - (void)__remove
    {
        [self.condition lock];
        NSLog(@"__remove - begin");
        
        if (self.data.count == 0) {
            // 等待
            [self.condition wait];
        }
        
        [self.data removeLastObject];
        NSLog(@"删除了元素");
        
        [self.condition unlock];
    }
    
    // 线程2
    // 往数组中添加元素
    - (void)__add
    {
        [self.condition lock];
        
        sleep(1);
        
        [self.data addObject:@"Test"];
        NSLog(@"添加了元素");
        // 信号
        [self.condition signal];
        
        // 广播
    //    [self.condition broadcast];
        [self.condition unlock];
        
    }
    @end
    
    

    NSConditionLock 条件锁加锁
    NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值

    条件锁加锁,对NSCondition的封装,可以设置线程依赖,多线程变成串行队列

    #import "NSConditionLockDemo.h"
    
    @interface NSConditionLockDemo()
    @property (strong, nonatomic) NSConditionLock *conditionLock;
    @end
    
    @implementation NSConditionLockDemo
    
    - (instancetype)init
    {
        if (self = [super init]) {
            self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
        }
        return self;
    }
    
    - (void)otherTest
    {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
        
        [[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
        
        [[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
    }
    
    - (void)__one
    {
        [self.conditionLock lock];
        
        NSLog(@"__one");
        sleep(1);
        
        [self.conditionLock unlockWithCondition:2];
    }
    
    - (void)__two
    {
        [self.conditionLock lockWhenCondition:2];
        
        NSLog(@"__two");
        sleep(1);
        
        [self.conditionLock unlockWithCondition:3];
    }
    
    - (void)__three
    {
        [self.conditionLock lockWhenCondition:3];
        
        NSLog(@"__three");
        
        [self.conditionLock unlock];
    }
    
    @end
    
    

    @synchronized 是对mutex递归锁的封装

    @synchronized是对mutex递归锁的封装
    源码查看:objc4中的objc-sync.mm文件
    @synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作

    image.png

    synchronized 底层代码

    • objc_sync_enter
    • objc_sync_exit

    objc_sync_enter

    // Begin synchronizing on 'obj'. 
    // Allocates recursive mutex associated with 'obj' if needed.
    // Returns OBJC_SYNC_SUCCESS once lock is acquired.  
    int objc_sync_enter(id obj)
    {
        int result = OBJC_SYNC_SUCCESS;
    
        if (obj) {
            SyncData* data = id2data(obj, ACQUIRE);
            assert(data);
            data->mutex.lock();
        } else {
            // @synchronized(nil) does nothing
            if (DebugNilSync) {
                _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
            }
            objc_sync_nil();
        }
    
        return result;
    }
    
    

    objc_sync_exit

    // End synchronizing on 'obj'. 
    // Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
    int objc_sync_exit(id obj)
    {
        int result = OBJC_SYNC_SUCCESS;
        
        if (obj) {
            SyncData* data = id2data(obj, RELEASE); 
            if (!data) {
                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
            } else {
                bool okay = data->mutex.tryUnlock();
                if (!okay) {
                    result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
                }
            }
        } else {
            // @synchronized(nil) does nothing
        }
        
    
        return result;
    }
    
    

    iOS线程同步方案性能比较

    性能又1->10 递减,
    os_unfair_lock性能最好,@synchronized性能最差

    1、os_unfair_lock
    2、OSSpinLock
    3、dispatch_semaphore
    4、pthread_mutex
    5、dispatch_queue(DISPATCH_QUEUE_SERIAL)
    6、NSLock
    7、NSCondition
    8、pthread_mutex(recursive)
    9、NSRecursiveLock
    10、NSConditionLock
    11、@synchronized
    ```
    
    

    相关文章

      网友评论

          本文标题:多线程:线程同步方案 各种锁

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