Answers:
很难证明程序是“线程安全的”。但是,可以具体和正式地定义术语“数据竞赛”。并且可以确定程序的特定运行的执行跟踪在时间上是否具有与跟踪的大小成比例的数据竞争。这种类型的分析至少可以追溯到1988年: Barton P. Miller,Chong-Deok Choi,“一种有效调试并行程序的机制”,Conf。在编上。郎 Dsgn。和Impl。(PLDI-1988):135-144。
给定执行的跟踪,我们首先在跟踪中的事件之间先定义一个发生在偏序之前的事件。给定两个事件和发生在同一线程上,则或。(同一线程上的事件形成了由编程语言的顺序语义给出的总顺序。) 同步事件(例如,它们可能是互斥体的获取和释放),在部分顺序之前给出了额外的线程间事件。(如果线程释放了一个互斥锁,然后线程获得了该互斥锁,则我们说释放发生在获取之前。)b a < b b < a S T
然后,给定两个数据访问(对不是同步变量的变量的读取或写入)和,它们访问相同的内存位置,但是通过不同的线程,并且其中或是写操作,我们说有一个数据- 如果和都不在和之间竞争。b a b a b a < b b < a
在C ++ 11标准是一个很好的例子。(相关的章节是在线提供的规范草案中的1.10。)C ++ 11区分同步对象(互斥对象和使用atomic<>
类型声明的变量)和所有其他数据。C ++ 11规范指出,如果数据访问全部没有数据争用,那么程序员可以在多线程程序的轨迹上推断数据访问是否顺序一致。
Helgrind工具(Valgrind的一部分)与一些商业工具(例如Intel Inspector XE)一样,执行这种基于事前发生的数据种族检测。现代工具中的算法基于保持与每个线程和同步相关的矢量时钟宾语。我认为这种使用矢量时钟进行数据竞赛检测的技术是Michiel Ronsse率先提出的。Koen De Bosschere:“ RecPlay:一个完全集成的实际记录/重放系统”,ACM Trans。计算 Syst。17(2):133-152,1999。
就排除比赛条件而言,这是确保程序正确性的一个非常困难的领域,这是并行处理的一种“脚跟”。程序正确性的最佳方法通常是避免使用低级原语,并使用确保线程同步的高级设计模式(例如,来自库)。假设开发人员将自己限制在“框架”内,则有一个模型CSP通过Hoare 传达顺序过程,该模型具有一些正确性证明。它与unix “管道和过滤器”具有一些概念上的相似性和时间顺序上的起源/重叠,尽管还没有发现两者之间的直接联系。
另外两个尝试通过设计模式提高并行化正确性的框架,并且为此目的具有大多数标准/已知算法/设计模式: