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 ...
随机推荐
- 通过adb命令查看SN、CID码等信息
用ADB命令来查看自己手机的相关硬件以及其他的参数信息,相信许多机友已经早已查看过,而新入门感兴趣的机友可以尝试一下. 运用这些ADB命令可以很直观的查看到你手机上的硬件与软件方面的详细信息. 下 ...
- linux下根据根据进程号查端口、根据端口号查进程号汇总,以及netstat的相关资料(工作中匮乏的知识)
根据端口查进程: lsof -i:port netstat -nap | grep port 根据进程号查端口: lsof -i|grep pid netstat -nap | grep pid 根据 ...
- leetcode 1041——困于环中的机器人
描述: 在无限的平面上,机器人最初位于 (0, 0) 处,面朝北方.机器人可以接受下列三条指令之一: "G":直走 1 个单位 "L":左转 90 度 &quo ...
- maven surefire入门
一.maven常用命令: mvn compile mvn install mvn test mvn clean mvn dependency:resolve -X #查看完整的debug信息!!! ...
- 拾遗:Go 单元测试
概念 回归测试:是指修改了旧代码之后,重新进行测试,以确保修改没有引入新的错误或导致其它代码产生错误: 单元测试:是指对软件中的最小可测试单元(单个函数或类)进行检查和验证 Test-Driven D ...
- python去除rpm仓库中同名低版本的包
编程思路1 遍历目标路径的rpm包并保存特性包列表: 2 利用python模块rpmUtils提取RPM包的特征信息:包名 版本号 架构 3 遍历特性列表中存在重复包名的rpm, 将低版本的rpm包 ...
- pycharm的第一次使用(其实并不是第一次)
file --> settings --> editor -->general --> change font size file --> settings --> ...
- Linux编程获取本机IP地址
使用函数getifaddrs来枚举网卡IP,当中使用到的结构体例如以下所看到的: struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in ...
- 标准 IO fread 与 fwrite 的使用(可以实现二进制流的读写)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void ...
- log4cplus TimeBasedRollingFileAppender
参考自:http://blog.csdn.net/u010607621/article/details/54944696 对于TimeBasedRollingFileAppender 这个日志appe ...