并发程序中数据竞争检测方法研究综述

**
站在巨人的肩膀上
一些思考

定义:

进程:一个程序的执行称为进程
线程:是操作系统能够进行运算调度的最小单位。
:多线程程序中引入锁机制,能够保证在某个时间点上,只能有一个线程进入临界区。
死锁:指两个或两个以上的进程,在执行过程中,因争夺资源而造成的一种互相等待的现象。
数据竞争是多线程程序中最为常见也是最为复杂的一种错误。由于并发条件下,信息不同步,产生读写误差,就可能会出现数据竞争。
硬件环境如下:CPU为Intel®Core™ i7-7700 @3.60 GHz(8核,8线程),内存为32.00GB。
软件环境如下:操作系统为Ubuntu 12.04 64位,插桩框架为插桩框架为Intel pin-2.12-58423-gcc.4.4.7-linux,
编译环境为gcc-4.9.4,g+±4.9.4,编程语言为C++11。
AdaptiveLock: Efficient Hybrid Data Race Detection Based on Real-World Locking Patterns
这篇论文提到在现实世界中大多数数据竞争是没有加锁保护引起的。
条件:
在同一个进程中有两个或更多的线程并发的访问同一内存地址。
至少有一个线程的访问时写(write)操
1.一个线程写入一个变量,另一个变量来读这个变量。
2.或者读之前,另一个线程写入时,这两个线程没有使用同步关系。
3.这两个线程访问同一片共享内存,并且没有明确的先后顺序关系,且至少有一个为写访问时,则会发生数据竞争。

向量时钟:现实场景中,往往会碰到并行,同时修改,导致db1和db2数据不一致。向量时钟可解决这一问题。

参考文献:
[25] YU J,NARAYANASAMY S,PEREIRA C,et al.Maple:ACoverage-Driven Testing Tool for Multithreaded Progr[…]

Inlel PIN 使用原理

PIN是intel公司开发的动态二进制插桩框架,可用于创建动态程序检测工具。
pin通过它提供的一些API,可以在二级制代码中插入一些探测函数,用于观察、记录、分析等
。比如内存、寄存器、控制流。
核心问题:在哪插入什么 如何插入
Pintool可以理解成在 Pin 重新生成可执行文件过程中,告诉 Pin 在某些位置插入某些代码。比如当前我所用的 zsim 就是一个 Pintool。
Instrumentation 粒度
Trace Instrumentation
调用 API:TRACE_AddInstrumentFunction

2.Instruction Instrumentation

调用 API:INS_AddInstrumentFunction

一次对一条 Instruction 做检测。

3.Image Instrumentation 和 Routine Instrumentation
检测 Multi-threaded Applications 以及避免 Deadlock(死锁)
在面对多线程时, Pin 提供了自有的锁与线程管理 API,Pintool 只能使用这些API。

对于多线程,Pin 在 每个 thread 开始和结束 提供 call-back(PIN_AddThreadStartFunction 和 PIN_Add_TreadFIniFunction)。这些 call-back使得 Pintool 方便 allocate 和 manipulate 线程的本地数据以及将这些数据存放在 thread-local storage(TLS)。

Pin 还提供 Pin-specific thread ID, 这个不同于 操作系统的 thread ID。这个 ID 可以被视为是线程数据 或者 Pin 用户锁数据的 索引值。

为避免 Deadlock ,Pin 要求在获取 lock 时遵循一定顺序(假设应用程序也有lock)。那么lock获取顺序应该是

应用程度 lock -> Pin internal lock -> Pintool Lock

在 Pintool 获取 lock 之前,Pin 通常或获得自己的内部锁(internal lock, 通过 PIN_GetLock) 。

后续会具体去谈 Pin 关于 Multi-thread 部分。

注:所有内容基于 Pin 3.2,不同 Pin 版本之间存在一定差异。
静态检测和动态检测对比:
动态检测优缺点:
优点:只检测在可执行期间实际发生地那些明显的数据竞争,不容易产生误报。
缺点:只考虑程序一个特定的执行路径,从而在本地检查程序。

基于LockSet datarace发生的原因:
1.对共享位置的访问没有保护锁。
2.没有连续锁;例如:访问时受到锁的保护,有时不受任何保护。
3.假连续锁(具有连续保护锁,但它们不一致)

静态检测工具

只分析程序源码,缺少程序运行时的信息,这会产生大量的误报,虚假的数据竞争。
常见地有Racerx\Locksmith\RELAY

动态检测工具

动态检测会产生高性能的开销,使程序的执行速度减慢了一个轻量级。
动态检测主要使用锁级法lockset、先发生于算法happens-before。
绝大多数的动态数据竞争检测工具都是基于如下几种算法:happens-before, lockset或混合模式(两者兼而有之)。
基于happens-before关系提出了使用逻辑时钟来动态的检测数据竞争。

Dji+检测方法:使用向量时钟的形式记录线程和共享内存空间的逻辑时钟。
hybrid算法:首先利用happens-before规则找到所有无确定先后关系的并发访问,然后利用lockset算法验证这些并发访问是否受到公共锁保护。
基于抽样的数据竞争检测方法研究
Pacer
FastTrack(2009)它是轻量级的的检测工具,它认为一个没有数据竞争的程序,在执行过程中,对内存空间的写访问是有序的,而只有多个线程对同一共享内存进行读访问才可能是并发的。
因此对写访问采用epoch形式的轻量级逻辑时钟,对只有并发的读访问采用向量时钟。这样来减少向量时钟操作,减少开销。
因此,从整体上来看,复杂度为O(1),但对于同步操作中的同步对象,向量时钟相关的操作复杂度是O(n)。

缺点:虽然能检测很多数据竞争,但是检测速度较慢。

LiteRace(2009)它也是轻量级的检测工具,使用抽样技术来选择性的监视内存访问,只对程序执行的选定部分进行采样和分析,首先是进行100%的采样率,全部采样,然后每当相应的线程调用一个函数时,对那些访问次数多的,经常访问的区域减少采样,而对那些很少访问的,可以设置较高的采样率,这样的话来减少内存访问,降低开销。
LiteRace实现的是函数级别的检测方法,对像Apache那样的应用程序有效,但对像FireFox的并发程序,可能不太友好。

缺点:虽然它的检测速度快,但会错过很多数据竞争。
解决方法:降低粒度,如指令级、语句级。提高检测效率。
Pacer(2010)
介绍了周期性抽样策略,它只在采样期间完全跟踪内存访问和同步操作,在非采样期间,它只检查竞争事件,
然而,Pacer基于动态采样(即在线进行采样策略),从而产生一定的基本开销。这样的开销使得Pacer不适合在用户站点上部署。

AtexRace(2017)
提出问题:为了解决线程本地采样,我们的洞察力是,是 否采样内存访问事件也应该取决于其他线程和已经观察到的执行。 也就是说,即使线程多次访问内存地址,如果第二个线程访问内存,我们可能仍然需要对其进行采样第一次的地址。我们的想法是保存和 存储来自以前运行的抽样信息。 除了从冷运行开始的第一次执行外,随后的执行加载累积的先前执行的采样信息。 虽然 这种方法会引起开销,但我们认为较少的采样与优化启发式 可以导致净效益。
但与Lite Race不同的是,Atex Race主要访问一对函数内部的样本,这些函数以前没有观察到同时执行的情况,包括 以前的执行。
首先,跨线程跟踪执行通常比线程本地跟踪产生更大的 开销。
其次,即使两个函数之前被观察到是并行执行的,数 据竞赛仍然可能在它们内部发生。
第三,由于AtexRace在不 同的执行中执行采样,而不是在单个执行中执行,因此它必 须有效地记录用于后续执行的函数交织信息。
这种检测工具是一种跨线程和跨执行的抽样方法,它是有选择的抽样当前和以前不经常看到的内存访问对,然后保存和存储抽样信息,提供之后多次重复测试使用,这样的话以后每次测试的开销会逐步降低,并不会漏报数据竞争。
AtexRace技术则是通过添加足够多的测试用例,在不同的运行线程间进行采样来达到减少时间开销的目的。
启发式算法
缺点:因为它是跨线程的跟踪执行,通常比线程本地的数据产生更大的开销。因为要记录使用的函数交织信息。
原因:竞争覆盖率问题,函数通常包含多个基本块(BBL),函数的执行并不意味着所有的BBL被执行。
解决办法:是将采样级别从函数降为BBL(然而这可能产生更多的开销),采样工具应尽可能少地采样内存访问,以减少内存开销。

缺点:(由李梦珂改进了基于采样技术的动态混合数据竞争检测算法)
AtexRace算法在大大降低检测开销的同时,能够得到与FastTrack相同的数据竞争检测效果,但在获得跨线程函数对的访存信息后,AtexRace算法并没有做任何处理,这些访存信息是否真正涉及数据竞争,有待进一步判定。
例如,在搜集到的两个函数对中,这两个函数没有访问共享变量或没有对共享变量执行写操作等,
图2中线程t1的函数f2和线程t2的函数f3同时执行时,只有f3对共享变量s2进行了写操作,f2并没有访问共享变量,第9行和第14行不会发生数据竞争,但AtexRace算法仍会把函数对〈f2,f3〉保留到函数对集合中。把这些不可能涉及数据竞争的函数对输入到检测器会产生大量的检测分析开销。
图2 采样示例在这里插入图片描述
据此,本文提出了改进策略,即在AtexRace算法获取到的跨线程内存访问操作中只保留真正涉及数据竞争的事件对,把不涉及数据竞争的访存信息过滤掉,
称该方法为预竞争检测[23]Yang Z , Yanan L , Dongwen Z , et al. Data race detection approach in concurrent programs[J]. Journal of Computer Applications, 2019.
并发程序中数据竞争检测方法-张杨 计算机应用

本文把一个访问事件表示为:Eventn:{Tid,variable,iswrite,lockset},Tid表示线程号,variable表示是否访问同一个共享变量,iswrite表示是否是写操作,

lockset表示获得锁集的情况。本文还定义了预数据竞争判定条件,即对于任意两个访问事件Eventt和Eventt′,存在如下条件:
见论文李梦珂:
AsampleLock算法是FastTrack和锁模式相结合的混合算法,两种算法相结合可有效降低误报率和漏报率。并且通过优化的采样技术可获取真正涉及数据竞争的跨线程内存访问对,将其作为检测阶段的输入,输出为一份检测报告。

李梦珂论文最新的采样方法
李梦珂论文
李梦珂[40] 等在LiteRace和FastTrack的基础上,提出了一种基于优化的FastTrack算法和锁模式的动态混合数据竞争检测算法AsampleLock,该算法采用锁模式进行动态数据竞争检测,来降低误报率和漏报率,并且利用采样技术,监控同一时刻同时运行的来自并发线程的函数对,通过预竞争检测获得真正涉及数据竞争的内存访问对,从而减小了数据竞争检测的开销。
最新的采样策略它利用硬件体系结构的代码和数据断点来支持其用于竞争检测的采样。
97.1%的数据竞争错误是由不受任何锁保护的访问引起的;2.9%的数据竞争错误是由两次访问受不同的锁保护引起的。AsampleLock算法就是基于此结论提出的。
本文针对上述问题做出改进,对于每一个共享内存单元的读写操作,都会保留全部的访存记录。

采样工具应尽可能地减少内存访问,以此来减少开销。

Vector clocks.
FASTTRACK和LITERACE在内的现有技术使用矢量时钟来实现精确的种族检测。
它们都减少了读写时的分析开销,但是同步操作下的分析仍需要O(n)时间,因此这些方法不会扩展到许多线程。相反,通过调整采样率,PACER可以扩展到许多线程。
Hybrid techniques.混合技术。混合技术结合了锁集和矢量时钟,以获得前者的性能和后者的准确性。
采样。使用全局采样来捕获跨线程内存交错[36]作为统计错误隔离的谓词。他们的方法无需复杂的分析(例如跟踪同步操作)即可发现多种并发错误类型。另一方面,PACER不需要查找故障即可发现种族,无需结合多个运行结果即可检测种族,并且使用全局采样机制,无需对两个访问都进行采样。

现有的轻量级检测工具存在问题:
(1)由于使用向量时钟算法(检测结果高度依赖于线程调度),而遭受假阴性(误报)。
(2)使用了粗粒度分析(函数级别),需降低粒度。
(3)检测精度,准备度比较高,但是开销比较大,速度慢
(4) 空间开销随着并行线程数线性增长。
(5)检测粒度:小的单元会丢失数据竞争,开销大;

动静结合检测方法:
虽然能弥补各自方法的一些缺点,但是在源程序运行时会引入大量的开销,同时也没有显著提升检测精度。

数据竞争通常表明严重的并发错误,这些错误很容易引入,但难以重现,理解和修复。甚至没有进行彻底的测试就可以找到所有竞争,因此必须部署可部署的竞争以实现高度健壮的软件。

先前的方法过于繁重,或者它们仅在查找竞争子集时有效。
本文介绍了数据竞争检测,它为每个竞争提供了与采样率相等的检测率,并增加了与采样率成比例的时间和空间开销。 PACER比以前的工作有了质的改进:其可调节的性能和准确性使其适合在各种部署环境中始终使用。
目前研究进展:
目前datarace检测和验证方法要么执行效率高,但精度偏低,要么检测精度高但执行效率偏低。
未来的工作:
1)提升datarace检测精度,借助一些同步分析技术,去除一些良性和错误的datarace.
之前的研究主要集中在纯动态,纯静态,可将能否结合动静结合的各自优势,全民提升检测准确度。
2)提升datarace检测效率
未来可考虑立足在使用动态datarace检测方法来分析验证过程中,被遗漏的datarace语句对。
3)完善数据竞争报告
可尝试探讨在报告datarace时,能够打印构成datarace的2个线程的上下文信息,优先呈现出可能导致严重后果的datarace。
4)智能精确的数据选取
使用数据挖掘等智能的方法进行数据的选取,精确地选取必要的数据,以较小的数据量获取较大的信息量,提高检测的性能和准确性。

以后的工作应评估不常见的竞争;考虑版本向量的最坏情况;并优化始终在非采样期间执行的检测。从较高的层次上讲,PACER的跨线程采样方法可能适用于其他并发错误。

基于采样技术的动态混合数据竞争检测算法
李梦珂
文中提出了一种基于优化的FastTrack算法和锁模式的动态混合数据竞争检测算法AsampleLock。
1)该算法利用采样技术,监控同一时刻同时运行的来自并发线程的函数对,通过预竞争检测获得真正涉及数据竞争的内存访问对,从而减小竞争检测分析开销;
2)为了减弱线程调度对算法相关性能的影响,AsampleLock算法采用nolock-hb关系来判断访问事件的并发关系;
3)采用map记录所有共享变量的读写信息,并采用锁模式进行动态数据竞争检测,降低漏报率和误报率。

本文算法在时间复杂度和检测率上都优于其他3种算法,但本文算法未能区分出恶性或良性数据竞争,这是下一步的研究方向。 从它的基础上改进。
未能区分出恶性或良性的数据竞争,我们要做的就是如何怎样才能区分出恶性和良性数据竞争,研究重点

增加数据竞争检测效率的混合算法 梁帅帅 李兰英

文章结合静态RELAY法和动态Eraser锁集法,利用数据流的静态法对共同锁集的判断和动态法对共同锁集的保护,有效地降低误检率和漏检率。
为减少因重复交织出现的冗余,提出使用重复检测器减少重复检测的数据竞争,提升了检测性能,降低了检测开销。

因很难确定程序操作实际影响到哪些内存、被访问的值是局部范围还是全局范围、是否通过参数传递到函数中,RELAY、Locksmith等方法能调用上下文敏感分析来确定访问内存的实际位置,但每个位置上持有哪些锁,程序操作获取和释放了哪些锁,这些锁是否有可能通过参数传入的结构派生而来的都无法确定。RELAY、Locksmith等方法在两个不同访问处,锁持有的锁集的交集进行判断是否为可疑数据竞争。Flanagan等人的先发生于算法提出更新时钟向量,通过时钟向量状态判断相关读写访问信息。
本文先进行上下文敏感分析,再使用Eraser[2]方法对相关锁集进行保护。
如果有可疑的数据竞争将被进行删除,随后再根据检测过程中检测出的可疑竞争所在位置的程序段进行分步骤重复检测,

方法思路:
首先使用静态测试工具找出所有可疑的数据竞争语句对。

消除数据竞争的措施:
1.为共享内存单元加上一致性锁保护。
2.利用条件变量等同步设施使两个访问之间形式一个。
3.固定的执行顺序。
4、线程同步 方法比如采用互斥量/读写锁。

自适应锁:
1) 几乎所有数据竞争 Bug 都是由于没有锁(0 锁定的竞争)而导致的,
(2) 一小部分数据竞争 Bug 是由两个访问引起的,每个访问都受锁保护,但两个锁是不同的(d 锁定的竞争)。
根据观察,AdaptiveLock仅维护用于检测0锁定和d锁定竞争的信息,而不是保留所有线程的所有共享访问的访问信息

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值