美文网首页
iOS多线程(6)-Lock

iOS多线程(6)-Lock

作者: WorldPeace_hp | 来源:发表于2018-04-05 17:16 被阅读0次
    • 为什么用锁:

      多线程编程中,如果对同一数据源进行读写操作就会造成不可预知的结果,所以我们应该尽量避免并发操作资源在线程之间共享,以减少线程间的相互作用,就需要一些同步工具,来确保当它们交互的时候是安全的。

    • 锁的种类:

      iOS开发中常用的锁有如下几种:

      1. @synchronized 同步锁
      2. NSLock 对象锁
      3. NSRecursiveLock 递归锁
      4. NSConditionLock 条件锁
      5. pthread_mutex 互斥锁(C语言)
      6. dispatch_semaphore 信号量实现加锁(GCD)
      7. OSSpinLock 自旋锁 (暂不建议使用,原因参见这里
    • 锁的性能对比:

      我们先来看一下网上的评测,几乎关于锁性能介绍的文章都用了这张图: work_time.png

      那根据这张图所描述的耗时对别正确吗?我们自己实际测试一下,看下边的测试代码:

      #import <pthread.h>
      #import <libkern/OSAtomic.h>
      
      #define CycleTime (1024*1024*32)
      
      - (void)testAction {
        NSTimeInterval time = [NSDate date].timeIntervalSince1970;
        
        //同步锁
        for (int i = 0; i < CycleTime; i++) {
            @synchronized(self) {
                
            }
        }
        NSLog(@"%f : work time of Synchronized",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //条件锁
        NSConditionLock *conditionLock = [[NSConditionLock alloc] init];
        for (int i = 0; i < CycleTime; i++) {
            [conditionLock lock];
            [conditionLock unlock];
        }
        NSLog(@"%f : work time of NSConditionLock",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //递归锁
        NSRecursiveLock *rsLock = [[NSRecursiveLock alloc] init];
        for (int i = 0; i < CycleTime; i++) {
            [rsLock lock];
            [rsLock unlock];
        }
        NSLog(@"%f : work time of NSRecursiveLock",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //互斥锁
        NSLock *mutexLock = [[NSLock alloc] init];
        for (int i = 0; i < CycleTime; i++) {
            [mutexLock lock];
            [mutexLock unlock];
        }
        NSLog(@"%f : work time of NSLock",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //互斥锁
        pthread_mutex_t mutex;
        pthread_mutex_init(&mutex, NULL);
        for (int i = 0; i < CycleTime; i++) {
            pthread_mutex_lock(&mutex);
            pthread_mutex_unlock(&mutex);
        }
        NSLog(@"%f : work time of pthread_mutex",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //信号量
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
        for (int i = 0; i < CycleTime; i++) {
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_semaphore_signal(semaphore);
        }
        NSLog(@"%f : work time of dispatch_semaphore",[NSDate date].timeIntervalSince1970-time);
        time = [NSDate date].timeIntervalSince1970;
        
        //自旋锁
        OSSpinLock spinlock = OS_SPINLOCK_INIT;
        for (int i = 0; i < CycleTime; i++) {
            OSSpinLockLock(&spinlock);
            OSSpinLockUnlock(&spinlock);
        }
        NSLog(@"%f : work time of OSSpinLock",[NSDate date].timeIntervalSince1970-time);
      }
      

      输出:

      2018-03-29 18:51:14.638390+0800 Lock[97416:4313533] 3.498765 : work time of Synchronized
      2018-03-29 18:51:16.987938+0800 Lock[97416:4313533] 2.349282 : work time of NSConditionLock
      2018-03-29 18:51:18.480868+0800 Lock[97416:4313533] 1.492687 : work time of NSRecursiveLock
      2018-03-29 18:51:19.286578+0800 Lock[97416:4313533] 0.805475 : work time of NSLock
      2018-03-29 18:51:20.029690+0800 Lock[97416:4313533] 0.742872 : work time of pthread_mutex
      2018-03-29 18:51:20.556899+0800 Lock[97416:4313533] 0.526966 : work time of dispatch_semaphore
      2018-03-29 18:51:20.909306+0800 Lock[97416:4313533] 0.352188 : work time of OSSpinLock
      

      看输出结果一目了然了,跟上图的评测结果一致。

    • 如何使用锁:

      1. @synchronized卖票例子:
      - (void)sycnAction {
        __block int ticketsCount = 5;
        
        void(^saleTickets)(void) = ^() {
            while (YES) {
                /*
                 注意点:
                 1.加锁的代码尽量少
                 2.添加的OC对象必须在多个线程中都是同一对象
                 3.优点是不需要显式的创建锁对象,便可以实现锁的机制。
                 4.@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
                 */
                
                //这里参数添加一个OC对象,一般使用self
                @synchronized(self) {
                    [NSThread sleepForTimeInterval:1];
                    if (ticketsCount > 0) {
                        ticketsCount--;
                        NSLog(@"Tickets = %d, Thread:%@",ticketsCount,[NSThread currentThread]);
                    }
                    else {
                        NSLog(@"Clear  Thread:%@",[NSThread currentThread]);
                        break;
                    }
                }
            }
        };
        
        NSLog(@"Start tickets count = %d, Thread:%@",ticketsCount,[NSThread currentThread]);
      
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            saleTickets();
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            saleTickets();
        });
      }
      
      1. NSLock互斥锁卖票例子:
      - (void)lockAction {
        __block int ticketsCount = 5;
        
        NSLock *lock = [[NSLock alloc] init];
        
        void(^lockSaleTickets)(void) = ^() {
            while (1) {
                [lock lock];
                
                [NSThread sleepForTimeInterval:1];
                if (ticketsCount > 0) {
                    ticketsCount--;
                    NSLog(@"Tickets= %d, Thread:%@",ticketsCount,[NSThread currentThread]);
                }
                else {
                    NSLog(@"Clear  Thread:%@",[NSThread currentThread]);
                    break;
                }
                
                [lock unlock];
            }
        };
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            lockSaleTickets();
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            lockSaleTickets();
        });
      }
      
      1. NSRecursiveLock递归锁卖票例子:
      - (void)recursiveLockAction {
      //    NSLock *lock = [[NSLock alloc] init];
        NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            static void(^TestMethod)(int);
            
            TestMethod = ^(int value) {
                [lock lock];
                if (value > 0) {
                    NSLog(@"value = %d",value);
                    [NSThread sleepForTimeInterval:1];
                    TestMethod(--value);
                }
                [lock unlock];
            };
            
            NSLog(@"Begain Test");
            TestMethod(5);
        });
      }
      
      1. NSConditionLock条件锁卖票例子:
      - (void)conditionLockActive {
        NSConditionLock *lock = [[NSConditionLock alloc] init];
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i = 0; i <= 5; i++) {
                [lock lock];
                NSLog(@"1.thread1 condition = %ld, i = %d",(long)lock.condition,i);
                [lock unlockWithCondition:i];
                NSLog(@"2.thread1 condition = %ld, i = %d",(long)lock.condition,i);
            }
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [lock lockWhenCondition:2];
            NSLog(@"thread2");
            [lock unlock];
        });
      }
      
      1. pthread_mutex_t互斥锁例子:
      - (void)pthreadMutexAction {
        __block pthread_mutex_t mutex;
        pthread_mutex_init(&mutex, NULL);
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(2);
            pthread_mutex_lock(&mutex);
            NSLog(@"任务2");
            
            pthread_mutex_unlock(&mutex);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            pthread_mutex_lock(&mutex);
            NSLog(@"任务1");
            pthread_mutex_unlock(&mutex);
        });
      }
      
      1. dispatch_semaphore_t信号量例子:
      - (void)semaphoreAction {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
        
        __block int count = 10;
        
        void(^TestMethod)(void) = ^() {
            while (YES) {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                if (count > 0) {
                    count --;
                    NSLog(@"value = %d, %@",count,[NSThread currentThread]);
                    [NSThread sleepForTimeInterval:1];
                }
                else {
                    NSLog(@"Done %@",[NSThread currentThread]);
                    break;
                }
                dispatch_semaphore_signal(semaphore);
            }
        };
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            TestMethod();
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            TestMethod();
        });
      }
      
      1. OSSpinLock自旋锁例子:
      - (void)spinAction {
        __block int tickets = 5;
        
        OSSpinLock spinlock = OS_SPINLOCK_INIT;
        
        void(^TestMethod)(void) = ^() {
            while (YES) {
                OSSpinLockLock(&spinlock);
                if (tickets > 0) {
                    tickets --;
                    NSLog(@"value = %d, %@",tickets,[NSThread currentThread]);
                    [NSThread sleepForTimeInterval:1];
                }
                else {
                    NSLog(@"Done %@",[NSThread currentThread]);
                    break;
                }
                OSSpinLockUnlock(&spinlock);
            }
        };
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            TestMethod();
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            TestMethod();
        });
      }
      
    • 死锁:待续....

    相关文章

      网友评论

          本文标题:iOS多线程(6)-Lock

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