Objective-C中不一样方式实现锁(二)(转载)

 
在上一文中,咱们已经讨论过用Objective-C锁几种实现(跳转地址),也用代码实际的演示了如何经过构建一个互斥锁来实现多线程的资源共享及线程安全,今天咱们继续讨论锁的一些高级用法。
1.NSRecursiveLock递归锁
平时咱们在代码中使用锁的时候,最容易犯的一个错误就是形成死锁,而容易形成死锁的一种情形就是在递归或循环中,以下代码:

    //主线程中html

    NSLock *theLock = [[NSLock alloc] init];安全

    TestObj *obj = [[TestObj alloc] init];多线程

    //线程1app

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{async

        static void(^TestMethod)(int);分布式

        TestMethod = ^(int value)spa

        {线程

            [theLock lock];3d

            if (value > 0)orm

            {

                [obj method1];

                sleep(5);

                TestMethod(value-1);

            }

            [theLock unlock];

        };

        

        TestMethod(5);

    });

    

    //线程2

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        sleep(1);

        [theLock lock];

        [obj method2];

        [theLock unlock];

    });

以上的代码中,就是一种典型的死锁状况,由于在线程1中的递归block中,锁会被屡次的lock,因此本身也被阻塞了,因为以上的代码很是的简短,因此很容易能识别死锁,但在较为复杂的代码中,就不那么容易发现了,那么如何在递归或循环中正确的使用锁呢?此处的theLock若是换用NSRecursiveLock对象,问题便获得解决了,NSRecursiveLock类定义的锁能够在同一线程屡次lock,而不会形成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操做。只有全部的锁住和解锁操做都平衡的时候,锁才真正被释放给其余线程得到。
2.NSConditionLock条件锁
当咱们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能彻底知足咱们的使用。由于普通的锁只能关心锁与不锁,而不在意用什么钥匙才能开锁,而咱们在处理资源共享的时候,多数状况是只有知足必定条件的状况下才能打开这把锁:
 

    //主线程中

    NSConditionLock *theLock = [[NSConditionLock alloc] init];

    

    //线程1

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        for (int i=0;i<=2;i++)

        {

            [theLock lock];

            NSLog(@"thread1:%d",i);

            sleep(2);

            [theLock unlockWithCondition:i];

        }

    });

    

    //线程2

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [theLock lockWhenCondition:2];

        NSLog(@"thread2");

        [theLock unlock];

    });

在线程1中的加锁使用了lock,因此是不须要条件的,因此顺利的就锁住了,但在unlock的使用了一个整型的条件,它能够开启其它线程中正在等待这把钥匙的临界地,而线程2则须要一把被标识为2的钥匙,因此当线程1循环到最后一次的时候,才最终打开了线程2中的阻塞。但即使如此,NSConditionLock也跟其它的锁同样,是须要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是能够随意组合的,固然这是与你的需求相关的。
3.NSDistributedLock分布式锁
以上全部的锁都是在解决多线程之间的冲突,但若是赶上多个进程或多个程序之间须要构建互斥的情景该怎么办呢?这个时候咱们就须要使用到NSDistributedLock了,从它的类名就知道这是一个分布式的Lock,NSDistributedLock的实现是经过文件系统的,因此使用它才能够有效的实现不一样进程之间的互斥,但NSDistributedLock并不是继承于NSLock,它没有lock方法,它只实现了tryLock,unlock,breakLock,因此若是须要lock的话,你就必须本身实现一个tryLock的轮询,下面经过代码简单的演示一下吧:
程序A:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];

        [lock breakLock];

        [lock tryLock];

        sleep(10);

        [lock unlock];

        NSLog(@"appA: OK");

    });

 
程序B:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];

        

        while (![lock tryLock]) {

            NSLog(@"appB: waiting");

            sleep(1);

        }

        [lock unlock];

        NSLog(@"appB: OK");

    });

先运行程序A,而后当即运行程序B,根据打印你能够清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒事后,程序B便打印出了appB:OK的输出,以上便实现了两上不一样程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,若是该文件或文件夹不存在,那么在tryLock返回YES时,会自动建立该文件/文件夹。在结束的时候该文件/文件夹会被清除,因此在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。
相关文章
相关标签/搜索