Objective-C中的同步线程的锁
概述
在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免。也就是给线程加锁。
因为Objective-C
是C
语言的超集。,严格的来说是真超集。所以C
语言当中的pthread
互斥锁在Objective-C
中也可以使用,但是Objective-C
中定义了本身自己的锁对象和锁协议,所以本篇介绍Objective-C
中的锁。
NSLock
NSLocking协议
@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
后面介绍的几种锁类型NSLock
,NSConditionLock
,NSRecursiveLock
,都实现了该协议可以统一用lock
与unlock
进行加锁与解锁。
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
放弃这个锁后,才可以在自己当前的线程重新获取到,线程恢复。如果一直获取不到这个锁那么线程将一直阻塞,所以lock
与unlock
这两个方法一定要成对出现。当然还有不阻塞调用锁的线程方法tryLock
与lockBeforeDate:
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中的同步线程的锁的更多相关文章
- c#中多线程同步Lock(锁)的研究以及跨线程UI的操作
本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...
- c#中多线程同步Lock(锁)的研究以及跨线程UI的操作 (转)
https://www.cnblogs.com/tommyheng/p/4104552.html 本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做de ...
- JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制
JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...
- JAVA语言规范-线程和锁章节之同步、等待和通知
JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...
- C++11 中的线程、锁和条件变量
转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通 ...
- JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this
JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...
- Java线程中的同步
1.对象与锁 每一个Object类及其子类的实例都拥有一个锁.其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁.单独的成员变量是不能被标明为同步的.锁只能用在使用了 ...
- ReentrantLock+线程池+同步+线程锁
1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...
- jvm高级特性(6)(线程的种类,调度,状态,安全程度,实现安全的方法,同步种类,锁优化,锁种类)
JVM高级特性与实践(十三):线程实现 与 Java线程调度 JVM高级特性与实践(十四):线程安全 与 锁优化 一. 线程的实现 线程其实是比进程更轻量级的调度执行单位. 线程的引入,可以把一个检查 ...
随机推荐
- HDU 1556 Color the ball【树状数组】
题意:给出n个区间,每次给这个区间里面的数加1,询问单点的值 一维的区间更新,单点查询,还是那篇论文里面讲了的 #include<iostream> #include<cstdio& ...
- javascipt入门
一.javascript简介 javascript:(基于对象的编程语言:内部很多对象,我们只需要使用即可,几乎不需要自己创建对象) ECMAScript DOM BOM 存放位置: 建议代码放到ht ...
- Python3基础笔记---线程与进程
参考博客:Py西游攻关之多线程(threading模块) 一.并发与并行的区别 并发:交替做不同事的能力并行:同时做不同事的能力 行话解释:并发:不同代码块交替执行的性能并行:不同代码块同时执行的性能 ...
- luogu P2117 小Z的矩阵(结论题)
题意 题解 这题有点水. 我们发现对答案有贡献的实际上只有左上到右下的对角线上的数. 因为不在这条对角线上的乘积都要计算两遍,然后%2就都没了... 然后就做完了. #include<iostr ...
- POJ3764 The xor-longest Path(字典树)
题意 给你一棵树,n个节点,n-1条边每条边i都有一个权值wi.定义任意两点间的权值为:这两点间的路径上的所有边的值的异或.比如a点和b点间有i,j,k三条边,那么ab两点间的权值为:wi^wj^wk ...
- BZOJ1567 [JSOI2008]Blue Mary的战役地图(二分+二维hash)
题意 问边长为n的两个正方形中最大的相等子正方形.(n<=50) 题解 用到了二维hash,感觉和一维的不太一样. 对于列行有两个不同的进制数然后也是通过类似前缀和的方法差分出一个矩形的hash ...
- vue-lazyload插件
更详细的内容,请移步 使用 npm install vue-lazyload --save //注册插件 import vueLazyload from 'vue-lazyload' Vue.use( ...
- 洛谷 P1403 [AHOI2005]约数研究
怎么会有这么水的省选题 一定是个签到题. 好歹它也是个省选题,独立做出要纪念一下 很容易发现在1~n中,i的因子数是n / i 那就枚举每一个i然后加起来就OK了 #include<cstdio ...
- centos安全配置
http://www.dedecms.com/knowledge/servers/linux-bsd/2012/0819/8506.html 引言: 我们必须明白:最小的权限+最少的服务=最大的安全 ...
- MySQL锁定状态查看命令
1 show processlist; SHOW PROCESSLIST显示哪些线程正在运行.您也可以使用mysqladmin processlist语句得到此信息.如果您有SUPER权限,您可以看到 ...