并行下的效率与安全

程序并行下的效率与安全是通过锁(互斥量、自旋锁)和lock-free(原子操作)方式来实现的,由于mutex修试下的临界区是串行的,首先记录下lock-free下的安全问题。

一、基础知识

CPU-Cache-Memory层次结构

1、cache line

叫做缓存行,是指cpu从内存中读取数据时总要把目标数据周围的一部分数据都读进来(局部一致性),这样一次读取的一组数据就是cache line,是缓存交换中的最小单位,不同机器存在差别。
cache line被读取进来后会拷贝到内核私有的L1/L2 cache下,当原子变量被修改后,会通知cpu的其他核心来同步变量所在的cache line(cpu一致性同步)。这就存在false sharing现象:当某个变量被多个核心共享时,一个核心对其进行修改就会导致其所在的cache line失效,需要重新从内存读取, cache line中的其他变量也要等待缓存同步而变慢,严重影响整体性能。因此并发编程中为避免这种情况:

  • 频繁被修改的变量要放到单独的cache line中,按cache line对齐。读远大于写的共享变量放到其他cache line里。
  • 对于计数器,被多个线程频繁修改,如果只是用作日志打印之类完全可以用thread local类型,日志打印时再合并变量值,性能能可能有几十倍的差距。

当然cache line同步是当共享变量能被其他核心可见的情况下,比如说全局的原子变量或者volatile修饰的变量。

2、内存序模型 Memoty Fence

原子操作只保证了对变量的访问控制,但是仍存在两种因素导致多线程代码运行结果不符合预期:

-为了提高运行效率,在每个机器周期内运行更多的指令,编译器和CPU会对指令进行重排。原则是单线程下互不依赖的指令进行重排,重拍后单线程下运行没有问题,多线程下就变的不确定了。

//Thread-1									//Thread-2
p.init();	//A							   if (a) 		//C
a = true;	//B							       p.run();	//D

由于单个线程下p和a是不依赖的,所以Thread-1/Thread-2重排后完全可能变成B->C->D->A,这样p就会在为初始化情况下执行,不符合预期。

  • 即使没有重排,p和a的值会在Thread-1执行后独立的同步到Thread-2所在核心的cache,Thread-2仍有可能在看到a==true时看到的是为初始化的p的值。

对解决指令重排,c++提供了6中内存序模型,常用的是Release/Acquire组合,write-release和read-acquire配对使用。详见下面例子。

memory order作用
memory_order_relaxed没有fencing作用, 原子操作默认使用。
memory_order_consume后面依赖此原子变量的访存指令勿重排至此条指令之前
memory_order_acquire后面访存指令勿重排至此条指令之前
memory_order_release前面访存指令勿重排至此条指令之后。当此条指令的结果对其他线程可见后,之前的所有指令都可见
memory_order_acq_relacquire + release语意
memory_order_seq_cstacq_rel语意外加所有使用seq_cst的指令有严格地全序关系

上面的例子更正为:

//Thread-1													
p.init();	//A							
a.store(true, std::memory_order_release);	//B	
			
//Thread-2
if (a.load(std::memory_order_acquire)) 		//C
	p.run();	//D

B指令的write-release保证了A->B,C指令的read-acquire保证了C->D,然后配对使用这一组会先执行write再执行read,就保证了A->B->C->D的执行顺序。

对于cache line的同步问题(可见性),memory fence只能保证可见性指令的顺序性,不能保证指令的可见性,详见:https://github.com/apache/incubator-brpc/blob/master/docs/cn/atomic_instructions.md#memory-fence

参考:
【1】https://github.com/apache/incubator-brpc/blob/master/docs/cn/atomic_instructions.md#memory-fence
【2】https://aaron-ai.com/docs/memory_reordering_simple_analysis/
【3】https://www.boost.org/doc/libs/1_56_0/doc/html/atomic/usage_examples.html
【4】https://www.codedump.info/post/20191214-cxx11-memory-model-2/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值