概述

在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免。也就是给线程加锁。

因为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多线程开发中的互斥锁解决方案,在此不多做介绍。

Objective-C中的同步线程的锁的更多相关文章

  1. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...

  2. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作 (转)

    https://www.cnblogs.com/tommyheng/p/4104552.html 本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做de ...

  3. JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

    JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...

  4. JAVA语言规范-线程和锁章节之同步、等待和通知

    JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...

  5. C++11 中的线程、锁和条件变量

    转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通 ...

  6. JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

    JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...

  7. Java线程中的同步

    1.对象与锁 每一个Object类及其子类的实例都拥有一个锁.其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁.单独的成员变量是不能被标明为同步的.锁只能用在使用了 ...

  8. ReentrantLock+线程池+同步+线程锁

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

  9. jvm高级特性(6)(线程的种类,调度,状态,安全程度,实现安全的方法,同步种类,锁优化,锁种类)

    JVM高级特性与实践(十三):线程实现 与 Java线程调度 JVM高级特性与实践(十四):线程安全 与 锁优化 一. 线程的实现 线程其实是比进程更轻量级的调度执行单位. 线程的引入,可以把一个检查 ...

随机推荐

  1. HDU 4190 Distributing Ballot Boxes【二分答案】

    题意:给出n个城市,n个城市分别的居民,m个盒子,为了让每个人都投上票,问每个盒子应该装多少张票 二分盒子装的票数, 如果mid<=m,说明偏大了,r应该向下逼近 ,r=mid 如果mid> ...

  2. Dapper Dapper-Extensions

    之前公司在开发项目的时候有用到过Dapper 仓储 以及IOC Castel .最近新项目上想使用上这些技术,决定新学习一下. 看了很多资料,发现几个比较容易菜鸟的我理解的,整理下来,找时间好好整理一 ...

  3. 解决Windows下git需要每次都要ssh-add的问题

    顽皮的很: 不知道怎么回事,每次打开git提交代码都需要ssh-add一下秘钥才可以正常提交: 不然就报错权限之类的问题: 怎么才能更方便一些? 卸了重装!我没试... 再或者是在 git 的安装目录 ...

  4. 12种CSS BUG解决方法与技巧

    一. 针对浏览器的选择器 这些选择器在你需要针对某款浏览器进行css设计时将非常有用. IE6及其更低版本,本文由52CSS.com整理,转载请注明出处! * html {} IE7及其更低版本 *: ...

  5. ajax 不执行

    1.get形式访问: 一个相同的URL 只有一个结果,所以 第二次访问的时候 如果 URL字符串没变化 浏览器是 直接拿出了第一次访问的结果,post则不会 解决办法: 1.url+new Date( ...

  6. ERROR in xxxx.js from UglifyJS——配置版本混杂版

    常规解决套路可以参考这篇:https://segmentfault.com/a/11... 我采用了上面的做法,依然没法解决.我采用的是vue-cli脚手架自动生成的项目结构: vue-cli版本 2 ...

  7. deque迭代器失效的困惑?

    在实现LRU算法的时候lru_list 開始用的是deque 可是由于害怕其在插入删除上的迭代器失效情况的诡异情况.遂用list取代之. 在数据量比較大的时候性能不是非常好.性能优化分析的时候决定用d ...

  8. URAL - 1243 - Divorce of the Seven Dwarfs (大数取模)

    1243. Divorce of the Seven Dwarfs Time limit: 1.0 second Memory limit: 64 MB After the Snow White wi ...

  9. POJ3370&amp;HDU1808 Halloween treats【鸽巢原理】

    题目链接: id=3370">http://poj.org/problem?id=3370 http://acm.hdu.edu.cn/showproblem.php?pid=1808 ...

  10. Perfect Rectangle(完美矩形)

    我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域. 每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1,2,2] ...