概述

我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生。

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就会对信号量-1
  • dispatch_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的更多相关文章

  1. iOS开发系列--并行开发其实很容易

    --多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的, ...

  2. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  3. iOS开发系列文章(持续更新……)

    iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...

  4. iOS开发系列--App扩展开发

    概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...

  5. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  6. iOS开发系列--通知与消息机制

    概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...

  7. iOS开发系列--数据存取

    概览 在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库.例如前面IOS开发系列-Objective-C之Foundation框架的文章中提到归档.plist文件存储, ...

  8. iOS开发系列--网络开发

    概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...

  9. iOS开发系列--C语言之基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...

随机推荐

  1. Vim用法AAAAA

    .linux系统中如何进入退出vim编辑器,方法及区别 我们当然要保存并退出了,然后下一步了.这时,我们要按键盘左上角的"ESC",留意到了没有?左下角的插入状态不见了,如图. 然 ...

  2. 3.4 redux 异步

    在大多数的前端业务场景中,需要和后端产生异步交互,在本节中,将详细讲解 redux 中的异步方案以及一些异步第三方组件,内容有: redux 异步流 redux-thunk redux-promise ...

  3. 1. Python版本的选择与安装

    Python综述 Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.Python是一种解释型.面向对象.动态数据类型的高级程序设计语言,它具有卓越的通 ...

  4. HDU 1392 Surround the Trees (凸包周长)

    题目链接:HDU 1392 Problem Description There are a lot of trees in an area. A peasant wants to buy a rope ...

  5. 【android】获取本机ip地址

    方法是利用网址:http://pv.sohu.com/cityjson?ie=utf-8,返回String类型的ip地址: public static String getNetIp() { Stri ...

  6. OSPF中DR和BDR到底是谁先选举出来的?

    在OSPF的DRBDR选举的过程中,DR的选举依靠的是hello报文,在two-way之后,交互hello报文完成DR/BDR的选举. 那么在每台路由器根据收到的所有hello报文,会构建自己接口的数 ...

  7. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

  8. 前端(七)—— 盒模型之display、overflow、隐藏、border、margin、样式支持,层级结构

    display.overflow.隐藏.border.margin.样式支持,层级结构 一.盒模型之display 1.三种样式 block 块 inline 内联/行内 inline-block 内 ...

  9. GCloud SDK 遇到的错误记录

    eclipse 环境 1.调用 SetAppInfo 方法返回 -1 语音id 和 key 设置正确 ,各种检测都没问题 解决办法 把安卓工程目录下 obj 文件价删除 ,把sdk 替换成以前能用的老 ...

  10. JS window对象 计时器setTimeout() setTimeout()计时器,在载入后延迟指定时间后,去执行一次表达式,仅执行一次。 语法: setTimeout(代码,延迟时间);

    计时器setTimeout() setTimeout()计时器,在载入后延迟指定时间后,去执行一次表达式,仅执行一次. 语法: setTimeout(代码,延迟时间); 参数说明: 1. 要调用的函数 ...