以太坊系列之四: 使用atomic来避免lock
使用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的更多相关文章
- 以太坊系列之十六: 使用golang与智能合约进行交互
以太坊系列之十六: 使用golang与智能合约进行交互 以太坊系列之十六: 使用golang与智能合约进行交互 此例子的目录结构 token contract 智能合约的golang wrapper ...
- 以太坊系列之十七: 使用web3进行合约部署调用以及监听
以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event) 上一篇介绍了使用golang进行智能合约的部署以及调用,但是使用go语言最大的一个问题是没法持续监听事件的发生. 比如 ...
- 以太坊系列之十六:golang进行智能合约开发
以太坊系列之十六: 使用golang与智能合约进行交互 以太坊系列之十六: 使用golang与智能合约进行交互 此例子的目录结构 token contract 智能合约的golang wrapper ...
- 以太坊系列之一: 以太坊RLP用法-以太坊源码学习
RLP (递归长度前缀)提供了一种适用于任意二进制数据数组的编码,RLP已经成为以太坊中对对象进行序列化的主要编码方式.RLP的唯一目标就是解决结构体的编码问题:对原子数据类型(比如,字符串,整数型, ...
- 以太坊系列之十八: 百行go代码构建p2p聊天室
百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...
- 以太坊系列之六: p2p模块--以太坊源码学习
p2p模块 p2p模块对外暴露了Server关键结构,帮助上层管理复杂的p2p网路,使其集中于Protocol的实现,只关注于数据的传输. Server使用discover模块,在指定的UDP端口管理 ...
- 以太坊系列之三: 以太坊的crypto模块--以太坊源码学习
以太坊的crypto模块 该模块分为两个部分一个是实现sha3,一个是实现secp256k1(这也是比特币中使用的签名算法). 需要说明的是secp256k1有两种实现方式,一种是依赖libsecp2 ...
- 以太坊系列之二: 单调时间monotime-以太坊源码学习
在程序中需要测量时间时最好使用monotime.Now()而不是time.Now(),相比之下前者更准确. 来个示例: func main() { var start, elapsed time.Du ...
- 以太坊系列之十一: 零起步使用remix开发智能合约
一步一步使用remix开发智能合约 最新版的remix(2017-8-3)只能使用在线开发了,已经没有离线版本了,并且好像在线版本要FQ才能访问(自行解决). 1.打开remix 注意地址如果是htt ...
随机推荐
- mysql实战优化之六:Order by优化 sql优化、索引优化
在MySQL中的ORDER BY有两种排序实现方式: 1.利用有序索引获取有序数据 2.文件排序 在使用explain分析查询的时候,利用有序索引获取有序数据显示Using index.而文件排序显示 ...
- PTA 银行排队问题之单队列多窗口服务(25 分)
银行排队问题之单队列多窗口服务(25 分) 假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙.当有窗口空闲时,下一位顾客即去该窗口处理事务.当有多个窗口可选择时,假 ...
- VC++使用TCHAR
#ifdef _UNICODE #define tcout wcout #define tcin wcin #else #define tcout cout #define tcin cin #end ...
- Android的按钮单击事件及监听器的实现方式
第一种:匿名内部类作为事件监听器类 大部分时候,事件处理器都没有什么利用价值(可利用代码通常都被抽象成了业务逻辑方法),因此大部分事件监听器只是临时使用一次,所以使用匿名内部类形式 的事件监听器更合适 ...
- virsh使用qemu+tcp访问远程libvirtd
因为ssh的不能访问 所以使用tcp进行对远程libvirtd进行连接访问,例如 virsh -c qemu+tcp://example.com/system 修改文件vim /etc/sysconf ...
- mysql跟踪执行的sql语句
修改my.cnf配置文件 /usr/local/mysql/bin/mysql --verbose --help | grep -A 1 'Default options' Default optio ...
- Setting up logs in NetBackup
For a given issue, it may be necessary to gather multiple logs. This MUST cover the time the issue ...
- Halcon学习之四:有关图像生成的函数
1.copy_image ( Image : DupImage : : ) 复制image图像 2.region_to_bin ( Region : BinImage : ForegroundGray ...
- ado connection string
Provider=SQLOLEDB.1;Password=123;Persist Security Info=True;User ID=sa;Initial Catalog=mydb;Data Sou ...
- 关于FPGA设计16位乘法器的两…
原文地址:关于FPGA设计16位乘法器的两种算法作者:ChrisChan 部分原代码如下: 用特权的右移算法虽复杂点,但节省不少LEs,如下图: 用左移算法尽管浅显易懂,但因每次都会从最右端移位,会占 ...