iOS中的锁机制

作者: 不简单的风度 | 来源:发表于2016-05-23 18:50 被阅读918次

    本文主要讨论OC中各种锁的使用。首先,创建一个用来测试的类。假设这个测试类是共享的资源,然后method1和method2是互斥的。
    测试类:

    
    
    #import "TestObject.h"
    
    @implementation TestObject
    
    - (void)method1
    {
        NSLog(@"%@",NSStringFromSelector(_cmd));
    }
    
    - (void)method2
    {
        NSLog(@"%@",NSStringFromSelector(_cmd));
    }
    
    @end
    
    

    1.使用NSLock实现的锁

    TestObject *obj = [[TestObject alloc] init];
    NSLock *lock = [[NSLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [lock lock];
        [obj method1];
        sleep(10);
        [lock unlock];
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);//以保证让线程2的代码后执行
        [lock lock];
        [obj method2];
        [lock unlock];
    });
    

    除lock和unlock方法外,NSLock还提供了tryLocklockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。

    2.使用synchronized关键字构建的锁

    
    TestObject *obj = [[TestObject alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized(obj){
            [obj method1];
            sleep(10);
        }
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        @synchronized(obj){
            [obj method2];
        }
    });
    
    

    @synchronized指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj)改为@synchronized(other),刚线程2就不会被阻塞,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。

    3.使用C语言的pthread_mutex_t实现的锁

    
    
    TestObject *obj = [[TestObject alloc] init];
    
    __block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        pthread_mutex_lock(&mutex);
        [obj method1];
        sleep(5);
        pthread_mutex_unlock(&mutex);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        pthread_mutex_lock(&mutex);
        [obj method2];
        pthread_mutex_unlock(&mutex);
    });
    
    

    由于pthread_mutex_t定义在C语言中的pthread.h,所以导入头文件要使用#include

    4.使用GCD来实现的”锁”

    以上代码构建多线程我们就已经用到了GCD的dispatch_async方法,其实在GCD中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量是有区别,具体差异请自行查阅信号量与互斥锁之间的区别)

    
    TestObject *obj = [[TestObject alloc] init];
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [obj method1];
        sleep(10);
        dispatch_semaphore_signal(semaphore);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [obj method2];
        dispatch_semaphore_signal(semaphore);
    });
    
    

    以上就是常用的锁机制,在网上查资料都说OSSpinLock 自旋锁效率是最高的,但是目前很多人都说自旋锁已经不再安全。如果算上OSSpinLock,各种锁的效率如下

    OSSpinLock > pthread_mutex > NSLock > semaphore > @Sych
    

    如果有有关于OSSpinLock是否安全的问题会及时更新。

    相关文章

      网友评论

        本文标题:iOS中的锁机制

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