NSLock/NSRecursiveLock/NSConditionLock/@synchronized

http://blog.sina.com.cn/s/blog_8c87ba3b0101ok8y.html

 
使用NSLock类
    在Cocoa程序中NSLock中实现了一个简单的互斥锁。所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
    除了标准的锁行为,NSLock类还增加了tryLock和lockBeforeDate:方法。方法tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程。相反,它只是返回NO。而lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
    下面的例子显式了你可以是NSLock对象来协助更新一个可视化显式,它的数据结构被多个线程计算。如果线程没有立即获的锁,它只是简单的继续计算直到它可以获得锁再更新显式。 
    BOOL moreToDo = YES; 
    NSLock *theLock = [[NSLock alloc] init]; 
    ... 
    while (moreToDo) { 
         
         
        if ([theLock tryLock]) { 
             
            [theLock unlock]; 
        } 
    }
4.6.3 使用@synchronized指令
    @synchronized指令是在Objective-C代码中创建一个互斥锁非常方便的方法。@synchronized指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)。然而在这种情况下,你不需要直接创建一个互斥锁或锁对象。相反,你只需要简单的使用Objective-C对象作为锁的令牌,如下面例子所示: 
    - (void)myMethod:(id)anObj 
    { 
        @synchronized(anObj) 
        { 
            // Everything between the braces is protected by the @synchronized directive. 
        } 
    }
    创建给@synchronized指令的对象是一个用来区别保护块的唯一标示符。如果你在两个不同的线程里面执行上述方法,每次在一个线程传递了一个不同的对象给anObj参数,那么每次都将会拥有它的锁,并持续处理,中间不被其他线程阻塞。然而,如果你传递的是同一个对象,那么多个线程中的一个线程会首先获得该锁,而其
他线程将会被阻塞直到第一个线程完成它的临界区。
    作为一种预防措施,@synchronized块隐式的添加一个异常处理例程来保护代码。该处理例程会在异常抛出的时候自动的释放互斥锁。这意味着为了使用@synchronized指令,你必须在你的代码中启用异常处理。了如果你不想让隐式的异常处理例程带来额外的开销,你应该考虑使用锁的类。
4.6.4 使用其他Cocoa锁
    以下个部分描述了使用Cocoa其他类型的锁。
·使用NSRecursiveLock对象
    NSRecursiveLock类定义的锁可以在同一线程多次获得,而不会造成死锁。一个递归锁会跟踪它被多少次成功获得了。每次成功的获得该锁都必须平衡调用锁住和解锁的操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。
    正如它名字所言,这种类型的锁通常被用在一个递归函数里面来防止递归造成阻塞线程。你可以类似的在非递归的情况下使用他来调用函数,这些函数的语义要求它们使用锁。以下是一个简单递归函数,它在递归中获取锁。如果你不在该代码里使用NSRecursiveLock对象,当函数被再次调用的时候线程将会出现死锁。               NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init]; 
    void MyRecursiveFunction(int value) { 
        [theLock lock]; 
        if (value != 0) { 
            --value; 
            MyRecursiveFunction(value); 
        }
        [theLock unlock]; 
    } 
    MyRecursiveFunction(5);
    注意:因为一个递归锁不会被释放直到所有锁的调用平衡使用了解锁操作,所以你必须仔细权衡是否决定使用锁对性能的潜在影响。长时间持有一个锁将会导致其他线程阻塞直到递归完成。如果你可以重写你的代码来消除递归或消除使用一个递归锁,你可能会获得更好的性能。
·使用NSConditionLock对象
    NSConditionLock对象定义了一个互斥锁,可以使用特定值来锁住和解锁。不要把该类型的锁和条件(参见“条件”部分)混淆了。它的行为和条件有点类似,但是它们的实现非常不同。
    通常,当多线程需要以特定的顺序来执行任务的时候,你可以使用一个NSConditionLock对象,比如当一个线程生产数据,而另外一个线程消费数据。生产者执行时,消费者使用由你程序指定的条件来获取锁(条件本身是一个你定义的整形值)。当生产者完成时,它会解锁该锁并设置锁的条件为合适的整形值来唤醒消费者线程,之后消费线程继续处理数据。
    NSConditionLock的锁住和解锁方法可以任意组合使用。比如,你可以使用unlockWithCondition:和lock消息,或使用lockWhenCondition:和unlock消息。当然,后面的组合可以解锁一个锁但是可能没有释放任何等待某特定条件值的线程。
    下面的例子显示了生产者-消费者问题如何使用条件锁来处理。想象一个应用程序包含一个数据的队列。一个生产者线程把数据添加到队列,而消费者线程从队列中取出数据。生产者不需要等待特定的条件,但是它必须等待锁可用以便它可以安全的把数据添加到队列。 
    id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; 
    while(true) { 
        [condLock lock]; 
        
        [condLock unlockWithCondition:HAS_DATA]; 
    }
    因为初始化条件锁的值为NO_DATA,生产者线程在初始化的时候可以毫无问题的获取该锁。它会添加队列数据,并把条件设置为HAS_DATA。在随后的迭代中,生产者线程可以把到达的数据添加到队列,无论队列是否为空或依然有数据。唯一让它进入阻塞的情况是当一个消费者线程充队列取出数据的时候。
    因为消费者线程必须要有数据来处理,它会使用一个特定的条件来等待队列。当生产者把数据放入队列时,消费者线程被唤醒并获取它的锁。它可以从队列中取出数据,并更新队列的状态。下列代码显示了消费者线程处理循环的基本结构。 
    while (true) { 
        [condLock lockWhenCondition:HAS_DATA]; 
         
        [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)]; 
        // Process the data locally. 
    }
·使用NSDistributedLock对象
    NSDistributedLock类可以被多台主机上的多个应用程序使用来限制对某些共享资源的访问,比如一个文件。锁本身是一个高效的互斥锁,它使用文件系统项目来实现,比如一个文件或目录。对于一个可用的NSDistributedLock对象,锁必须由所有使用它的程序写入。这通常意味着把它放在文件系统,该文件系统可以被所有运行在计算机上面的应用程序访问。
    不像其他类型的锁,NSDistributedLock并没有实现NSLocking协议,所有它没有lock方法。一个lock方法将会阻塞线程的执行,并要求系统以预定的速度轮询锁。以其在你的代码中实现这种约束,NSDistributedLock提供了一个tryLock方法,并让你决定是否轮询。
    因为它使用文件系统来实现,一个NSDistributedLock对象不会被释放除非它的拥有者显式的释放它。如果你的程序在用户一个分布锁的时候崩溃了,其他客户端无法访问该受保护的资源。在这种情况下,你可以使用breadLock方法来打破现存的锁以便你可以获取它。但是通常应该避免打破锁,除非你确定拥有进程已经死亡并不可能再释放该锁。
    和其他类型的锁一样,当你使用NSDistributedLock对象时,你可以通过调用unlock方法来释放它。

NSLock/NSRecursiveLock/NSConditionLock/@synchronized的更多相关文章

  1. 多线程 (三)iOS中的锁

    锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...

  2. 多线程(三) iOS中的锁

    锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...

  3. IOS高级开发之多线程(五)NSOperation 2

    接着看NSOperation.NSOperationQueue线程间的通信: 应用场景:比如我们经常把一些耗时的操作比如下载图片放在子线程,那么当这个完成之后,我们就需要回到主线程,这个时候就需要用到 ...

  4. iOS开发系列-线程同步技术

    概述 多线程的本质就是CPU轮流随机分配给每条线程时间片资源执行任务,看起来多条线程同时执行任务. 多条线程同时访问同一块资源,比如操作同一个对象.统一变量.同一个文件,就会引发数据错乱和数据安全的问 ...

  5. iOS中的几种锁的总结,三种开启多线程的方式(GCD、NSOperation、NSThread)

    学习内容 欢迎关注我的iOS学习总结--每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary OC中的几种锁 为什么要引入锁 ...

  6. 谈谈iOS中的锁

    1 前言 近日工作不是太忙,刚好有时间了解一些其他东西,本来打算今天上午去体检,但是看看天气还是明天再去吧,也有很大一个原因:就是周六没有预约上!闲话少说,这里简单对锁来个简单介绍分享. 2 目录 第 ...

  7. iOS 线程安全

    线程安全: 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题.就好比几个人在同一时修改同一个表格,造成数据的错乱. 解决多线程安全问题的方法 方法一:互斥锁(同步锁) @synchroni ...

  8. iOS 中的各种锁

    在日常开发过程中,为了提升程序运行效率,以及用户体验,我们经常使用多线程.在使用多线程的过程中,难免会遇到资源竞争问题.我们采用锁的机制来确保线程安全. 线程安全 当一个线程访问数据的时候,其他的线程 ...

  9. iOS开发系列--并行开发其实很容易

    --多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的, ...

随机推荐

  1. UrlEncode编码/UrlDecode解码 - 站长工具

    http://tool.chinaz.com/tools/urlencode.aspx

  2. javascript之简单的选择排序法

    基本思想: 比对数组中元素,相等者输出元素在数组的下标,否则就输出没找到! 代码如下: function Orderseach(array,findVal){ var temp = false; // ...

  3. hibernate实现有两种配置,xml配置与注释配置。

    (1):xml配置:hibernate.cfg.xml (放到src目录下)和实体配置类:xxx.hbm.xml(与实体为同一目录中) <?xml version='1.0' encoding= ...

  4. 解决git pull 命令失效,不能从远程服务器上拉取代码问题

    用时候在用Git pull命令的时候不管用,拉取不下来远程分支上的代码,是因为本地分支和远程分支没有建立关联. 处理这种问题很简单就按照提示执行命令即可:git branch --set-upstre ...

  5. MySQL的外键是什么和它的作用

    从上图可以看见,表1添加一个外键,这个外键就是表2中的学号字段,那么这样表1就是主表,表2就是子表.所以结合2张表就能保持数据的一致性.完整性. 外键的一些事项:1.表1可以有一个或者多个外键,也可以 ...

  6. tomcat的文件路径 servelet的配置 以及maven中的WEB-INF的路径

    Tomcat JavaWeb应用的组成结构 开发JavaWeb应用时,不同类型的文件有严格的存放规则,否则不仅可能会使web应用无法访问,还会导致web服务器启动报错 WebRoot →Web应用所在 ...

  7. python 跨语言数据交互、json、pickle(序列化)、urllib、requests(爬虫模块)、XML。

    Python中用于序列化的两个模块 json     用于[字符串]和 [python基本数据类型] 间进行转换 pickle   用于[python特有的类型] 和 [python基本数据类型]间进 ...

  8. 总结一下安装linux系统经验-版本选择-安装ubuntu

    linux版本选择: 初次接触,建议选 Ubuntu 或者 Fedora,这两个发行版都很容易上手,而且两者都有很强大的中文社区,遇到问题比较容易解决,而且都有国内的源,安装或者更新软件时体验相对会好 ...

  9. 百万级数据查询到datatable中,提示内存溢出

    参考资料: http://group.cnblogs.com/topic/32230.html

  10. emlog在nginx中添加rewrite规则

    rewrite ^/(post|record|sort|author|page)-([-]+)\.html$ /index.php?$=$; rewrite ^/tag-(.+)\.html$ /in ...