概述

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

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. 9. DMA

    9.1 介绍 Direct memory access(DMA) 直接存储器访问. 这两个DMA控制器总共有16个流(每个控制器8个),每个流用于管理来自一个或多个外围设备的内存访问请求.每个流总共可 ...

  2. Centos 能ping通域名和公网ip但是网站不能够打开,服务器拒绝了请求。打开80端口解决。

    博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/10/29/centos-%E8%83%BDping%E9%80%9A%E5%9F%9F%E ...

  3. JDK8之新特性扩展篇

    之前分篇章讲了一些JKD8中添加的新特性,还有一些新特性这里也一并讲下. BASE64 base64编码解码已经被加入到了jdk8中了. import java.nio.charset.Standar ...

  4. (数据科学学习手札60)用Python实现WGS84、火星坐标系、百度坐标系、web墨卡托四种坐标相互转换

    一.简介 主流被使用的地理坐标系并不统一,常用的有WGS84.GCJ02(火星坐标系).BD09(百度坐标系)以及百度地图中保存矢量信息的web墨卡托,本文利用Python编写相关类以实现4种坐标系统 ...

  5. 从零开始搭建系统2.5——Apollo安装及配置

    参见https://github.com/ctripcorp/apollo/wiki/Quick-Start安装即可

  6. 6358. 【NOIP2019模拟2019.9.15】小ω的仙人掌

    题目 题目大意 给你一串二元组\((a_i,b_i)\)的数列. 求最小的区间\([l,r]\)长度,满足\([l,r]\)中的每个二元组选或不选,使得\(\sum a_i=w\)且\(\sum b_ ...

  7. PHP ftp_rawlist() 函数

    定义和用法 ftp_rawlist() 函数返回 FTP 服务器上指定目录中文件的详细列表. 语法 ftp_rawlist(ftp_connection,dir,recursive) 参数 描述 ft ...

  8. bzoj_auto_submiter(辣鸡Py毁我青春系列)

    听说你们的bzoj小号都很厉害? 不如试试bzoj金坷垃——bzoj_auto_submiter! 把所有的代码拖进解压后的文件夹,然后双击run.cmd. 看到有chrome浏览器窗口弹出来不要慌, ...

  9. centos6|centos7防火墙区别 | 网络配置区别

    CentOS 6 Linux防火墙 service iptables status (功能描述:查看防火墙状态) chkconfig iptables –list (功能描述:查看防火墙开机启动状态) ...

  10. NX二次开发-UFUN设置工程图PNG图片长度UF_DRF_set_image_width

    #include <uf.h> #include <uf_drf.h> UF_initialize(); //插入PNG char* file_name = "D:\ ...