本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景。然后再聊一下Atomic的代码实现。Atomic主要负责多线程下的原子操作,负责共享资源的同步一致性。而在Atomic中就是使用到了Posix互斥锁和递归锁。在聊上述内容之前,我们先来回顾一下Swift语言中延迟执行defer的使用方式,在之前Swift编程的相关博客中也涉及到了defer的使用方式。defer因为Atomic使用到了延迟操作,所以下方我们再做一个defer的简单回顾。

一、Defer延迟执行

在本篇博客之所以聊defer延迟执行,是因为在Atomic的代码实现中,使用了defer{}来为操作加的锁。具体的说是在操作前进行加锁,然后紧接着使用defer{}进行解锁,稍后我们会进行介绍。Swift中的Defer延迟执行是比较常用的,其用法也是比较简单的。下方就是我们列举了一个示例,该示例比较简单。首先我们输出a,然后使用defer块执行输出b的语句,然后就是输出c,最后是使用defer块输出d,具体代码如下。

  

在看上述代码输出结果时,我们可以先预测一下输出结果,是输出“abcd”还是“acbc”还是“acdb”呢?下方就是上述代码片段的输出结果。从下方代码片段中我们不难看出,其结果为“acdb”。从结果中我们不难看出defer{}块的执行顺序是在该作用域结束之前从后往前执行。

  

根据上述代码片段以及输出结果,我们可以画出下方这个运行简图,如下所示。因为下方这个简图并不复杂,在此就不做过多赘述了。

  

二、Posix互斥锁

互斥锁的概念就不做过多赘述了,简单的说就是防止多个线程同时修改一块共享区域,导致数据不同步的情况发生而添加的锁。互斥锁的互斥是线程的互斥,也就是说添加互斥锁的代码块在同一个时间点上只允许一个线程对这块共享区域进行操作,其他线程若想对该块区域进行操作的话,需要等待之前的互斥锁打开后方可进入。

下方这个PosixThreadMutex类是Atomic的代码实现中封装的Posix互斥锁。在该代码实现中主要调用了C语言中的线程互斥锁的相关函数。下方锁的使用方式,稍后再聊Atomic类的时候会使用到下方的这个互斥锁。

  

三、递归锁

接下来我们来看一下递归锁,在Atomic的代码实现中也使用到了递归锁。“递归锁”顾名思义就是在递归中使用的锁,普通锁在一个线程中是不能被重用的,也就是说一个普通锁被上锁后,你就不能再次调用上锁的方法了,这样会出问题的。等普通锁被解锁后,你才可以对其进行上锁。针对普通锁的不可重用性,我们给出了下方示例,如下所示。

  

上述代码片段比较简单,对普通锁连续执行了两次lock,然后执行我们的代码块,之后就是执行了两次unlock。该代码使用普通锁的步骤其实是与递归函数中使用普通锁的场景是一样的。当递归实现函数是,执行第一次递归时,添加了一个普通锁,在锁未打开时,第二次递归时又会执行一下上锁。这种场景与上述代码片段是一样的。因为普通锁在同一个线程中的不可重用性,所以上述代码会产生死锁DeadLock。下方截图就是上述代码片段所执行的结果:

  

我们将上述代码中的NSLock普通锁修改成NSRecursiveLock递归锁后,如下。下方的代码就可以正确执行。因为递归锁可以在同一个线程中重复的使用。具体如下所示:

  

既然是递归锁,那么接下来我们就在递归函数中来使用一下递归锁。在递归函数执行使用锁时,本质上是多次使用一个锁。也就是在一个锁未上锁时再次对其上锁。下方就是递归锁在递归函数中使用的简单示例。

  

四、Atomic原子操作的具体代码实现

聊完互斥锁和递归锁后,接下来我们来看一下ReactiveSwift中的原子操作Atomic类的具体代码实现。Aotmic中使用了上述我们聊的Posix互斥锁来进行的原子操作。下方就是Atomic类的代码实现。

从下方代码片段中我们不难看出,在value读取和修改时都会进行加锁和解锁操作。当然,解锁的代码是放在defer{}的语句块中进行操作的。在Atomic.swift文件中还有一个RecursiveAtomic类,也就是负责递归原子操作的。RecursiveAtomic与Atomic类的不同之处在于前者使用的是递归锁,负责在递归操作时保持原子操作。而后者使用的是互斥锁。RecursiveAtomic的代码与Atomic类的代码类似,在此就不做过多赘述了。

  

今天的博客就先到这儿,下篇博客我们会继续解析ReactiveSwift框架中的其他内容。

上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #ffffff }
span.s1 { }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #ffffff }
span.s1 { }

ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁的更多相关文章

  1. ReactiveSwift源码解析(八) SignalProducer的代码的基本实现

    在前面几篇博客中我们详细的聊了ReactiveSwift中的Bag.Event.Observer以及Signal的使用方式和代码实现.那么在接下来的这几篇博客中,我们就依附于之前博客的基础上来聊一聊S ...

  2. ReactiveSwift源码解析(三) Signal代码的基本实现

    上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...

  3. ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  4. Laravel源码解析之model(代码)

    本篇文章给大家带来的内容是关于Laravel源码解析之model(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 前言 提前预祝猿人们国庆快乐,吃好.喝好.玩好,我会在电视上看 ...

  5. ReactiveSwift源码解析(十二) MutableProperty基本代码实现

    前两篇博客我们分别聊了ReactiveSwift框架中的负责标记对象的生命周期的类Lifetime以及负责原子性操作的Atomic类的具体代码实现.前两篇博客之所以聊Lifetime以及Atomic的 ...

  6. ReactiveSwift源码解析(一) Event与Observer代码实现

    ReactiveCocoa这个框架是做什么用的本篇博客就不做过多赘述了,什么是"响应式编程"也不多聊了,自行Google吧.本篇博客的主题是解析ReactiveCocoa框架中的核 ...

  7. ReactiveSwift源码解析(二) Bag容器的代码实现

    今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...

  8. ReactiveSwift源码解析(四) Signal中的静态属性静态方法以及面向协议扩展

    上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...

  9. ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现

    本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式.在之前的<iOS开发之ReactiveCocoa下的MVVM>的博客中我们已经聊过combineLatest( ...

随机推荐

  1. Idea调试显示切换数据源的设置

    使用IDEA调试时,如果遇到相同方法会在编辑器上提示切换到哪个项目,因为手滑点了Disable,所以导致后来就不提示了,记录下设置方法.

  2. String详细学习

    学这些东西,就像是扎马步.小说里郭靖学不会招数,就会扎马步.搞JS,内力还是必须要深厚,深厚,深厚. 1,stringObject.slice(start,end) slice() 方法可提取字符串的 ...

  3. 第一章:pip 安装 和 卸载 django

    1. 在dos命令行中输入 pip 如下命令进行安装: 安装最新的版本的 Django 命令如下: pip install django 安装 指定版本的 Django 命令如下: pip insta ...

  4. Python3组合数据类型(元组、列表、集合、字典)语法

    一.序列类型(字符串,元组(),列表[]) 序列类型支持in,len(),分片[],迭代,5种内置序列类型:bytearray,bytes,list,str,tuple(元组). 1.元组可以嵌套(如 ...

  5. 如何用webpack实现自动化的前端构建工作流

    什么是自动化的前端构建流? 1. 自动补全css私有前缀,自动转化less\sass为css,自动转化es6\vue\jsx语法为js,自动打包小图片为base64以减少http请求,自动给js,cs ...

  6. webstrom一键上传github及使用

    对于webstrom是我参加it修真园时就推荐使用的,其他编辑器我也没什么使用过.读大学的时候还是比较喜欢 Notepad++. 现在说一下webstrom主要的关键点吧! 一.实现一键上传githu ...

  7. ZooKeeper快速学习

    "一入Java深似海",过去自身对于分布式的接触,始终处于使用别人构建的框架的水平,最多就是在nginx配置一下第4层的负载均衡(最后有介绍).随着java使用深入,本文将重点理解 ...

  8. 【学习笔记】C# 封装和继承

    封装 封装是实现面向对象程序设计的第一步 封装就是将数据.方法等集合在一个个单元中,我们称之为类 封装的意义在于保护代码/数据,屏蔽复杂性 继承 继承是所有面向对象语言不可缺少的部分 继承是为了实现类 ...

  9. 关于table表格td里内容是数字而且太长不换行的问题

    <p>table{table-layout:fixed}</p><p>table td{word-wrap:break-word}</p><p&g ...

  10. *更新*无需root,一条命令强制全屏模式

    未root的系统,必须通过pc端运行adb命令进行设置,因此请开启开发者选项中的adb调试模式,用usb连接电脑和手机,运行下面的代码强制开启全屏模式,立即生效:全屏沉浸: adb shell set ...