• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Objective-C中的同步线程的锁

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

概述

在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免。也就是给线程加锁。
因为Objective-CC语言的超集。,严格的来说是真超集。所以C语言当中的pthread互斥锁在Objective-C中也可以使用,但是Objective-C中定义了本身自己的锁对象和锁协议,所以本篇介绍Objective-C中的锁。

NSLock

NSLocking协议

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end

后面介绍的几种锁类型NSLock,NSConditionLock,NSRecursiveLock,都实现了该协议可以统一用lockunlock进行加锁与解锁。


NSLock使用

    NSLock *lock = [[NSLock alloc] init];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [lock lock];                //获取锁
        NSLog(@"lock success");
        sleep(5);
        NSLog(@"sleep end");
        [lock unlock];              //放弃之前获取的锁
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [lock lock];               //获取锁,如果获取不到阻塞当前线程直到获取到锁
        NSLog(@"remove lock");
        [lock unlock];             //放弃获取到的锁
    });

输出结果

 lock success
 sleep end
 remove lock

NSLock对象发送lock消息时先检查能不能获取到这个锁,如果此时在其他线程中正在使用这个锁那么阻塞当前线程一直等待其他线程使用完这个锁unlock放弃这个锁后,才可以在自己当前的线程重新获取到,线程恢复。如果一直获取不到这个锁那么线程将一直阻塞,所以lockunlock这两个方法一定要成对出现。当然还有不阻塞调用锁的线程方法tryLocklockBeforeDate:


tryLock
tryLock尝试获取锁,如果获取不到返回NO,反之YES,不会阻塞当前调用它的线程

    NSLock *lock = [[NSLock alloc] init];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [lock lock];                //获取锁
        NSLog(@"lock success");
        sleep(5);
        NSLog(@"sleep end");
        [lock unlock];              //放弃之前获取的锁
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        if ([lock tryLock])         //尝试获取锁,如果获取不到返回NO,不会阻塞该线程
        {
            NSLog(@"remove lock");
            [lock unlock];
        }
        else{
            NSLog(@"obtain failure");
        }
    });

输出结果

lock success
obtain failure
sleep end

获取失败是因为当前锁正在其他线程中使用。如果当前锁没有使用那么会返回YES
lockBeforeDate
lockBeforeDate阻塞调用它的线程,如果给定时间内不能够获取锁那么放弃获取并恢复线程。

    NSLock *lock = [[NSLock alloc] init];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [lock lock];                //获取锁
        NSLog(@"lock success");
        sleep(5);
        NSLog(@"sleep end");
        [lock unlock];              //放弃之前获取的锁
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:3];
        if ([lock lockBeforeDate:date]) //尝试在未来的3s内获取锁,并阻塞该线程,如果3s内获取不到恢复线程
        {
            NSLog(@"remove lock");
            [lock unlock];
        }
        else{
            NSLog(@"obtain failure");
        }
    });

输出结果

 lock success
 obtain failure
 sleep end

如果3s内获取不到则返回NO,否则返回YES

@synchronized

synchronized对一个对象提供锁定和解锁机制。synchronized会阻塞调用它的线程

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        @synchronized (self) {
            [self logging:@"lock success"];
            sleep(5);
            [self logging:@"sleep end"];
        }
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        @synchronized (self)    //等到上面线程执行完后才回执行下面的代码,此时会阻塞当前线程
        {
            [self logging:@"remove lock"];
        }
    });

输出结果

 lock success
 sleep end
 remove lock

上面对自身对象进行加锁直到上面第一个GCD全部执行结束才会执行下面加锁的代码。
注意
Objective-C类自身也是对象所以可以对这些类对象使用synchronized,此时是对整个对象类型进行线程同步。例如:

    @synchronized ([self class]) {
    }

NSConditionLock

NSConditionLock条件锁,获取锁时必须与之前设置解锁的条件一样时才可以获取到,否则当前线程一直阻塞,直到条件一致时线程才可以恢复。
最典型的例子就是生产者-消费者场景,当数据为空时生产者生产数据此时消费者不能够获取数据,生产者生产数据后,消费者处理数据,直到消费者处理所有数据后,数据又为空,此时生产者继续生产数据。示例代码如下:

    enum {NO_DATA_IN_QUEUE = 0,HAS_DATA_IN_QUEUE};
    NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:NO_DATA_IN_QUEUE];

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES) {
            [conditionLock lockWhenCondition:NO_DATA_IN_QUEUE];
            NSLog(@"insert data");
            sleep(3);
            NSLog(@"intset success");
            [conditionLock unlockWithCondition:HAS_DATA_IN_QUEUE];
        }
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES) {
            [conditionLock lockWhenCondition:HAS_DATA_IN_QUEUE];
            NSLog(@"delete data");
            sleep(3);
            NSLog(@"delete success");
            [conditionLock unlockWithCondition:NO_DATA_IN_QUEUE];
        }
    });

输出结果:

 insert data
 intset success
 delete data
 delete success
 insert data
 intset success
 delete data
 delete success
 ...

NSRecursiveLock

NSRecursiveLock递归锁,当我们对一个递归函数同步线程时会在同一个线程多次获取锁,导致线程死锁,NSRecursiveLock可以在同一个线程多次获取锁不会死锁。

NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

       static void (^recursive)(int count);
        recursive = ^(int count){
            [recursiveLock lock];
            if (count>0) {
                NSLog(@"success lock");
                sleep(3);
                recursive(--count);
            }
            [recursiveLock unlock];
        };
        recursive(3);

    });

上面这种情况如果使用NSLock在没有解锁时继续获取锁,就会造成死锁导致线程一致堵塞。

NSDistributedLock

NSDistributedLock是Mac多线程开发中的互斥锁解决方案,在此不多做介绍。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
objective-c常用数学方法 -发布时间:2022-07-12
下一篇:
iOS从手机相册选择一张照片并显示 Objective-C发布时间:2022-07-12
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap