zoukankan      html  css  js  c++  java
  • oc中不同方式实现锁

    今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @implementation TestObj

    - (void)method1
    {
        NSLog(@"%@",NSStringFromSelector(_cmd));
    }

    - (void)method2
    {
        NSLog(@"%@",NSStringFromSelector(_cmd));    
    }

    @end

    1.使用NSLock实现的锁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //主线程中
    TestObj *obj = [[TestObj alloc] init];
    NSLock *lock = [[NSLock alloc] init];

    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [lock lock];
    [obj method1];
    sleep(10);
    [lock unlock];
    });

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

    看到打印的结果了吗,你会看到线程1锁住之后,线程2会一直等待走到线程1将锁置为unlock后,才会执行method2方法。

    NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。

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

    当然在Objective-C中你还可以用@synchronized指令快速的实现锁:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //主线程中
    TestObj *obj = [[TestObj alloc] init];

    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    @synchronized(obj){
    [obj method1];
    sleep(10);
    }
    });

    //线程2
    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实现的锁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //主线程中
    TestObj *obj = [[TestObj alloc] init];

    __block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);

    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    pthread_mutex_lock(&mutex);
    [obj method1];
    sleep(5);
    pthread_mutex_unlock(&mutex);
    });

    //线程2
    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定义在pthread.h,所以记得#include 
    4.使用GCD来实现的”锁”
    以上代码构建多线程我们就已经用到了GCD的dispatch_async方法,其实在GCD中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量与锁是有区别,具体差异参加信号量与互斥锁之间的区别):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //主线程中
    TestObj *obj = [[TestObj alloc] init];
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

    //线程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);
    });

    //线程2
    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);
    });

    至于代码产生的效果当然和上一例是一模一样的,关于信号机制,熟悉C编程的你肯定也不会陌生的,关于GCD中更多关于dispatch_semaphore_t的信息,可以跳转到本博客的这一往篇文章:GCD介绍(三): Dispatch Sources

    好了,以上就是我所列举了几种方式来实现锁,当然锁大多数情况下也是配合多线程一起使用的,关于多线程编程,我这儿就不赘述了。

  • 相关阅读:
    通过JavaMail发送(群发)邮件示例(内含附件图片) 代码复制可用
    需要把获取系统的当前时间存入库里 获取时是String类型,库里是Datetime类型 String 转化 Date
    用canvas和原生js写的一个笨鸟先飞的小游戏(暂时只有一个关卡)
    Svg和canvas的区别,伪类选择器有哪些(归类)
    微信web网页动态增减输入框,搜索框,基于jQuery weui、jQuery 实现无限插入数据,动态数据生成,外加高德地图POI和根据坐标获取位置信息的页面
    vue 使用tinymce富文本编辑器
    mamp环境下navicat无法链接本地mysql
    tp5 系统变量输出
    开始项目注意事项
    jQuery weui实现下拉刷新事件
  • 原文地址:https://www.cnblogs.com/fanjing/p/4543611.html
Copyright © 2011-2022 走看看