iOS开发系列-Lock
概述
我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生。
iOS中锁之前的性能的图标排行:

开发中常接触的就是NSLock与@synchronized,其它的后续在研究。
NSLock
NSLock是Foundation提供的类,NSLock的API很少也很简单。常用的就几个方法
- (void)lock;
- (void)unlock;
- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;
lock跟unlock会是成对出现,如果是同一个锁对象lock多处代码。后加锁的代码要想执行必须要等前面加锁的代码先执行完毕并解锁才可执行。
如下示例代码
NSLock *lock = [NSLock new];
//Thread 1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 尝试加速ing...");
[lock lock];
sleep(5);//睡眠5秒
NSLog(@"线程1业务处理代码处理");
[lock unlock];
NSLog(@"线程1解锁成功");
});
//Thread 2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 尝试加速ing...");
[lock lock];
NSLog(@"线程2业务处理代码处理");
[lock unlock];
NSLog(@"线程2解锁成功");
});
控制台输出

线程1跟线程2是两条线程并发执行的,线程1的业务处理逻辑代码先被加锁,当线程2执行到lock实例再次调用lock加锁,其实lock实例已经加过锁了已经无法再加锁此时线程2就一直等待直到之前的锁解锁,5s之后线程1解锁,线程2此时加锁成功就继续执行后续代码。可以看出NSLock是线程堵塞的。
上面的lock方式会阻塞线程,直到之前的lock解锁。NSLock还提供了一个方法
- (BOOL)lockBeforeDate:(NSDate *)limit;
参数传入的是时间,表示会在传入的时间内尝试加锁,若能加锁则执行加锁操作并返回YES,反之返回NO。
NSLock *lock = [NSLock new];
//Thread 1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 尝试加速ing...");
[lock lock];
sleep(5);//睡眠5秒
NSLog(@"线程1业务处理代码处理");
[lock unlock];
NSLog(@"线程1解锁成功");
});
//Thread 2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 尝试加速ing...");
BOOL x = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4]]; //从现在开始4s内尝试加锁若能加锁则返回YES,反之返回NO
if (x) {
NSLog(@"-------------尝试加锁成功!!!!");
NSLog(@"线程2业务处理代码处理");
[lock unlock];
}else{
NSLog(@"-------------尝试加锁失败!!!!");
}
NSLog(@"线程2解锁成功");
});
}
线程2执行lockBeforeDate:现在开始的4s内尝试加锁,线程休眠5s,线程2在4s内尝试加锁会失败,返回NO。继续执行后续代码不会一直等待线程1解锁。

dispatch_semaphore 信号量
dispatch_semaphore_t信号量使用主要有如下几个函数
dispatch_semaphore_create(long value);
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
dispatch_semaphore_signal(dispatch_semaphore_t dsema);
先说下dispatch_semaphore_t信号量使用的原理。
- 在
dispatch_semaphore_create初始化信号量传入一个初始值value,API说明这个value要大于0 dispatch_semaphore_wait就会对信号量-1dispatch_semaphore_signal就会对信号量+1
为了更好的理解,初始化的信号量就好比一个停车位,一开始这个停车位就在dispatch_semaphore_create给确定了。如果有车来了停车位-1,相当与调用了dispatch_semaphore_wait,信号量-1。如果车位已经满了又来了车那么就需要等待。当有其它车开走了后停车位+1,相当于调用了dispatch_semaphore_signal,信号量+1。有了车位,等待的车就可以停车了。当然如果停车位满了后续的车辆可以不用一直等待,可以设置一个时间,如果在此时间内还没有车位就不等待了。
// 初始化信号量 设置信号量的值为1
dispatch_semaphore_t signal = dispatch_semaphore_create(1); //传入值必须 >=0, 若传入为0则阻塞线程并等待timeout,时间到后会执行其后的语句
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 等待ing");
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER ); //signal 值 -1
sleep(5);
NSLog(@"线程1");
dispatch_semaphore_signal(signal); //signal 值 +1
NSLog(@"线程1 发送信号");
NSLog(@"--------------------------------------------------------");
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 等待ing");
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER );
NSLog(@"线程2");
dispatch_semaphore_signal(signal);
NSLog(@"线程2 发送信号");
});
控制台输出:

这里dispatch_semaphore_wait传入的尝试锁的时间是DISPATCH_TIME_FOREVER就一直等待,自己可以需求传入时间。比如
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);
iOS开发系列-Lock的更多相关文章
- iOS开发系列--并行开发其实很容易
--多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的, ...
- iOS开发系列--Swift语言
概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...
- iOS开发系列文章(持续更新……)
iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...
- iOS开发系列--App扩展开发
概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...
- iOS开发系列--Swift进阶
概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...
- iOS开发系列--通知与消息机制
概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...
- iOS开发系列--数据存取
概览 在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库.例如前面IOS开发系列-Objective-C之Foundation框架的文章中提到归档.plist文件存储, ...
- iOS开发系列--网络开发
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- iOS开发系列--C语言之基础知识
概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...
随机推荐
- MFS分布式文件系统【4】客户端的挂载MFS存储空间
挂载基于MooseFS 分布式文件,客户端主机必须安装FUSE软件包(FUSE版本号至少2.6,推荐版本号大于2.7的fuse) [root@master ~]# rpm -qa|grep fuse ...
- webstorm vue eslint 自动修正配置
原文:https://medium.com/@netczuk/even-faster-code-formatting-using-eslint-22b80d061461 https://stackov ...
- MS Sql添加描述信息 及其他信息
--查询某个表的描述 SELECT * FROM fn_listextendedproperty (NULL, 'user', 'dbo', 'table', '(表名)',NULL, NULL) - ...
- vue-router 使用二级路由去实现子组件的显示和隐藏
在需求中有一个这样的情况:一个组件在主组件和另外的组件中引用,且点击主组件和这个组件分别有相应得切换事件. 一开始的时候我是没有划分组件,把它们放到主组件内,这样便于切换,但是主主件内有独立的部分需要 ...
- cocos构建的android项目的返回键相应
@Override public boolean dispatchKeyEvent(KeyEvent event) { //返回键 cocosActivity不相应onbackPressed和onKe ...
- Linux 进程间通信 信号(signal)
1. 概念: 1)信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式 2)信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件. 3)如果 ...
- BCZM : 1.9
有n个学生参加见面会,分别对m个研究组中的若干个感兴趣,为了满足所有学生的要求,每个学生都能参加自己感兴趣的见面会,如果每个见面会的时间为t,如何安排才能使得所有见面会的总时间最短? 分析: 先建立模 ...
- noip 2014 总结
2014 年的noip 已经结束了,成绩从个人而言不是特别的理想,从今年题的逗的程度,本来是个xxx 就被玩脱了= = 当然现在后悔事没有用的了,不过第二天全屏技术的在最后一小时看到了两道题的错误,然 ...
- 我们能从java的HelloWorld学到什么?
这是每个Java程序员都知道的.虽然简单,但是从一个简单的问题可以引入更深的思考.在这篇文章中,我们将讨论这个简单的程序.如果能更多的帮到你,请留下宝贵的意见. HelloWorld.java pub ...
- NX二次开发-UFUN获取点在面上U,V方向的位置UF_MODL_ask_face_parm【转载】
NX11+VS2013 #include <uf.h> #include <uf_ui.h> #include <uf_modl.h> #include <u ...