使用atomic来避免lock

在程序中为了互斥,难免要用锁,有些时候可以通过使用atomic来避免锁,
从而更高效.

下面给出一个以太坊中的例子,就是MsgPipeRW,从名字Pipe可以看出,

他实际上就是一个pipe,相比大家对pipe已经比较熟悉了,我就不多解释了.

type MsgPipeRW struct {
w chan<- Msg
r <-chan Msg
closing chan struct{}
closed *int32
} //创建一个MsgPipeRw
func MsgPipe() (*MsgPipeRW, *MsgPipeRW) {
var (
c1, c2 = make(chan Msg), make(chan Msg)
closing = make(chan struct{})
closed = new(int32)
rw1 = &MsgPipeRW{c1, c2, closing, closed}
rw2 = &MsgPipeRW{c2, c1, closing, closed}
)
return rw1, rw2
}
pipe就像水管一样,这里MsgPipe创建了两根水管,可以自由双向流动,rw1写,rw2就可以
读到,rw2写,rw1就可以读到.原理也很简单,因为rw1写和rw2操作的是同一个chan Msg,反之亦然. 关键是这里的closed,可以想想rw1,rw2很有可能在不同的goroutine发生读写关闭等操作,
这时候要同时访问closed这个变量,难免会发生冲突,我们看看如何避免. closed如果为0表示没有关闭,1表示已经关闭,就不应该再进行读写了.
// 从pipe中读取一个msg
func (p *MsgPipeRW) ReadMsg() (Msg, error) {
//这里不能直接*p.closed==0,要使用atomic.LoadInt32来访问
if atomic.LoadInt32(p.closed) == 0 {
...
}
return Msg{}, ErrPipeClosed
} // 写的时候也一样
func (p *MsgPipeRW) WriteMsg(msg Msg) error {
if atomic.LoadInt32(p.closed) == 0 {
...
}
return ErrPipeClosed
}

读写消息只是读取互斥变量,没有发生写入,下面来看看close的时候如何写入

func (p *MsgPipeRW) Close() error {
if atomic.AddInt32(p.closed, 1) != 1 { //避免锁,
// someone else is already closing
atomic.StoreInt32(p.closed, 1) // avoid overflow
return nil
}
close(p.closing)
return nil
}

atomic.AddInt32能够避免我们一般这样的写法发生的并发访问.

if *p.closed==0 {
*p.closed+=1
}

感兴趣的可以修改代码试试,采用*p.closed==0这种方式,会不会造成崩溃,测试代码如下

func TestMsgPipeConcurrentClose(t *testing.T) {
rw1, _ := MsgPipe()
for i := 0; i < 10; i++ {
go rw1.Close()
}
}

atomic看似神奇的避免了锁,实际上这需要处理器的特殊指令支持,尤其是发生在多和处理器上时,atomic指令

会保证对特定地址的锁定.

atomic相对于lock的最大优势就是他只是一条特殊指令,不用发生系统上下文切换,我们都知道系统上下文切换

代价要大得多.

以太坊系列之四: 使用atomic来避免lock的更多相关文章

  1. 以太坊系列之十六: 使用golang与智能合约进行交互

    以太坊系列之十六: 使用golang与智能合约进行交互 以太坊系列之十六: 使用golang与智能合约进行交互 此例子的目录结构 token contract 智能合约的golang wrapper ...

  2. 以太坊系列之十七: 使用web3进行合约部署调用以及监听

    以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event) 上一篇介绍了使用golang进行智能合约的部署以及调用,但是使用go语言最大的一个问题是没法持续监听事件的发生. 比如 ...

  3. 以太坊系列之十六:golang进行智能合约开发

    以太坊系列之十六: 使用golang与智能合约进行交互 以太坊系列之十六: 使用golang与智能合约进行交互 此例子的目录结构 token contract 智能合约的golang wrapper ...

  4. 以太坊系列之一: 以太坊RLP用法-以太坊源码学习

    RLP (递归长度前缀)提供了一种适用于任意二进制数据数组的编码,RLP已经成为以太坊中对对象进行序列化的主要编码方式.RLP的唯一目标就是解决结构体的编码问题:对原子数据类型(比如,字符串,整数型, ...

  5. 以太坊系列之十八: 百行go代码构建p2p聊天室

    百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...

  6. 以太坊系列之六: p2p模块--以太坊源码学习

    p2p模块 p2p模块对外暴露了Server关键结构,帮助上层管理复杂的p2p网路,使其集中于Protocol的实现,只关注于数据的传输. Server使用discover模块,在指定的UDP端口管理 ...

  7. 以太坊系列之三: 以太坊的crypto模块--以太坊源码学习

    以太坊的crypto模块 该模块分为两个部分一个是实现sha3,一个是实现secp256k1(这也是比特币中使用的签名算法). 需要说明的是secp256k1有两种实现方式,一种是依赖libsecp2 ...

  8. 以太坊系列之二: 单调时间monotime-以太坊源码学习

    在程序中需要测量时间时最好使用monotime.Now()而不是time.Now(),相比之下前者更准确. 来个示例: func main() { var start, elapsed time.Du ...

  9. 以太坊系列之十一: 零起步使用remix开发智能合约

    一步一步使用remix开发智能合约 最新版的remix(2017-8-3)只能使用在线开发了,已经没有离线版本了,并且好像在线版本要FQ才能访问(自行解决). 1.打开remix 注意地址如果是htt ...

随机推荐

  1. python selenium中iframe切换、window切换方法

    一.selenium中iframe切换方法: 方法一:switch_to.frame frame函数中提供了三种定位方法:by index, name, or webelement. driver.s ...

  2. 1088 Rational Arithmetic

    题意: 给出两个分式(a1/b1 a2/b2),分子.分母的范围为int型,且确保分母不为0.计算两个分数的加减乘除,结果化为最简的形式,即"k a/b",其中若除数为0的话,输出 ...

  3. JS面向对象编程,对象,属性,方法。

    document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...

  4. MyBatis多表映射demo

    三个实体类,作者.文章和评论. public class Author { private int id; private String username; private String nickna ...

  5. Three.js导入gltf模型和动画

    核心代码 复杂的3D模型一般都是用第三方建模工具生成,然后加载到three中 three官方推荐使用gltf格式的文件,代表编辑器是blender 本文生成了自定义生成了一个blender模型,并且应 ...

  6. Python Twisted系列教程2:异步编程初探与reactor模式

    作者:dave@http://krondo.com/slow-poetry-and-the-apocalypse/  译者:杨晓伟(采用意译) 这个系列是从这里开始的,欢迎你再次来到这里来.现在我们可 ...

  7. leetcode892

    这道题因为有0的情况,因此不能使用投影的方法,需要遍历每一个元素,单独处理. class Solution { public: int surfaceArea(vector<vector< ...

  8. django -- url 的 name 属性

    在html的form中使用给url定义的name值,可以在修改url时不用在修改form的src. urls.py from django.conf.urls import url from myte ...

  9. 【278】◀▶ Python 数学函数说明

    参考:Python 数学函数说明 目录: 一.Python 数学函数 二.Python 随机数函数 三.Python 三角函数 四.Python 数学常量 一.Python 数学函数   函数 返回值 ...

  10. C# 文件打印

    Process pr = new Process();                     pr.StartInfo.FileName = “C:\test.xls”;               ...