要使用此工具,必须--tool=drd
在Valgrind命令行上指定 。
DRD是用于检测多线程C和C ++程序中的错误的Valgrind工具。该工具适用于使用POSIX线程原语的任何程序,或者使用构建在POSIX线程图元之上的线程概念。
在程序中使用多线程有两个可能的原因:
-
模拟并发活动。与单个线程中多个活动的状态复用相比,将一个线程分配给每个活动可以是一个很好的简化。这就是为什么大多数服务器软件和嵌入式软件都是多线程的。
-
同时使用多个CPU内核来加速计算。这就是为什么许多高性能计算(HPC)应用程序是多线程的。
多线程程序可以使用以下一个或多个编程范例。哪个范例适合取决于应用程序类型。多线程编程范例的一些例子是:
-
锁定。通过线程共享的数据可以通过锁定进行并发访问。例如POSIX线程库,Qt库和Boost.Thread库直接支持该范例。
-
消息传递。线程之间没有共享数据,但线程通过相互传递消息来交换数据。消息传递范例的实现示例是MPI和CORBA。
-
自动并行化 编译器将顺序程序转换为多线程程序。原始程序可能包含也可能不包含并行化提示。这种并行化提示的一个例子是OpenMP标准。在本标准中,定义了一组指令,告诉编译器如何并行化C,C ++或Fortran程序。OpenMP非常适合于计算密集型应用。例如,开源图像处理软件包正在使用OpenMP来最大化具有多个CPU内核的系统的性能。GCC支持4.2.0版的OpenMP标准。
-
软件事务内存(STM)。通过事务更新线程之间共享的任何数据。每个交易之后,验证是否存在任何冲突的交易。如果存在冲突,则该事务被中止,否则就被提交。这是一种所谓的乐观态度。有一个支持STM的Intel C ++编译器的原型。关于向海湾合作委员会增加STM支持的研究正在进行之中。
只要这些范例的实现基于POSIX线程图元,DRD就支持多线程编程范例的任何组合。然而,DRD不支持直接使用例如Linux'futexes的程序。尝试用DRD分析这些程序将导致DRD报告许多假阳性。
POSIX线程,也称为Pthreads,是Unix系统上最广泛使用的线程库。
POSIX线程编程模型基于以下抽象:
-
共享地址空间。在同一进程内运行的所有线程共享相同的地址空间。所有数据(无论是否共享)都由其地址标识。
-
定期加载和存储操作,允许从同一进程中运行的所有线程共享的内存读取值或向其写入值。
-
原子存储和加载修改存储操作。虽然这些在POSIX线程标准中没有提及,但大多数微处理器都支持原子内存操作。
-
线程。每个线程表示并发活动。
-
同步对象和这些同步对象的操作。在POSIX线程标准中定义了以下类型的同步对象:互斥体,条件变量,信号量,读写器同步对象,障碍和自旋锁。
哪些源代码语句生成哪些内存访问取决于正在使用的编程语言的内存模型。C和C ++语言还没有一个确定的内存模型。对于内存模型草案,另见文档 WG21 / N2338:并发内存模型编译器的后果。
有关POSIX线程的更多信息,另请参阅单一UNIX规范版本3,也称为 IEEE Std 1003.1。
根据程序中使用的多线程范例,可能会出现以下一个或多个问题:
-
数据竞赛 一个或多个线程访问相同的内存位置,而没有足够的锁定。大多数但不是所有的数据竞赛都是编程错误,并且是微妙和难以发现的错误的原因。
-
锁定争用 一个线程通过持有锁太长来阻止一个或多个其他线程的进度。
-
不正确的使用POSIX线程API。POSIX线程API的大多数实现已针对运行速度进行了优化。这样的实现不会对某些错误抱怨,例如当互斥体被另一个线程解锁时,而不是获得互斥锁上的锁的线程。
-
僵局。当两个或多个线程无限期地等待彼此时,会发生死锁。
-
虚假分享 如果在不同处理器核心上运行的线程经常访问位于同一高速缓存行中的不同变量,那么由于高速缓存线的频繁交换,这将减慢涉及的线程。
尽管数据竞赛发生的可能性可以通过有纪律的编程风格来降低,但是在开发多线程软件时,必须使用自动检测数据竞赛的工具。DRD可以检测这些,以及锁定争用和不正确使用POSIX线程API。
由多线程程序执行的加载和存储操作的结果取决于执行内存操作的顺序。此订单由以下决定:
-
由同一线程执行的所有存储器操作都按 程序顺序执行,即由程序源代码确定的顺序和先前加载操作的结果。
-
同步操作确定由不同线程执行的存储器操作的某些排序约束。这些排序约束称为同步顺序。
程序顺序和同步顺序的组合称为 发生之前的关系。这一概念首先由S.Adve等人在“ 检测弱记忆体系数据竞赛”(ACM SIGARCH Computer Architecture News,v.19 n.3,p.234-243,1991年5月)中定义。
如果两个操作都是由不同的线程执行的,则 两个内存操作冲突,指的是相同的内存位置,其中至少有一个是存储操作。
如果所有冲突的存储器访问是通过同步操作排序的,则多 线程程序是数据竞争的。
确保多线程程序无数据资源的众所周知的方法是确保遵守锁定规则。例如,可以将互斥体与每个共享数据项相关联,并且在访