多线程程序能否具有确定性?

时间:2010-09-30 12:10:16

标签: multithreading non-deterministic

通常认为多线程程序是非确定性的,这意味着如果它崩溃,则几乎不可能重新创建导致该条件的错误。一个人真的不知道接下来会运行什么线程,以及何时会再次被抢占。

当然,这与操作系统线程调度算法有关,而且事实上人们不知道接下来要运行什么线程,以及它将有效运行多长时间。 程序执行顺序也起到了作用等作用......

但是如果你有用于线程调度的算法怎么办?如果你知道什么线程正在运行,那么多线程程序会变成“确定性的”,就像在,你将能够重现崩溃吗?

8 个答案:

答案 0 :(得分:11)

了解算法实际上不会让您预测何时会发生什么。在执行程序或线程时发生的各种延迟取决于环境条件(自由RAM - >交换,其他繁忙任务,进入中断等)。

如果您要将多线程程序映射到顺序执行,并且您的线程本身对其行为具有确定性,那么您的整个程序可能是确定性的,并且“并发”问题可以重现。当然,在那时他们不再是并发问题了。

如果您想了解更多信息,http://en.wikipedia.org/wiki/Process_calculus非常有趣。

答案 1 :(得分:6)

我的意见是:技术上没有(但在数学上是)。您可以编写确定性线程算法,但是在一段合理的时间后,您可以非常难以预测应用程序的状态非确定性

答案 2 :(得分:3)

有一些工具(在开发中)会尝试以某种可预测的方式创建竞争条件,但这是关于前瞻性测试,而不是重建“野外的错误”。

CHESS就是一个例子。

答案 3 :(得分:3)

可以在虚拟多线程机器上运行程序,其中每个线程的虚拟循环分配是通过一些完全确定的过程完成的,可能使用伪随机生成器(可以使用常量生成)在每个程序运行之前)。另一个可能更有趣的可能性是拥有一个虚拟机,它可以在'splatter'模式下运行线程之间交替(几乎任何它们触摸​​的变量都会使其值变为'未知'到其他线程)和'cleanup'模式(其中具有已知操作数的操作结果将是可见的并且对于其他线程是已知的。我希望这种情况可能有点类似于硬件仿真:如果每个门的输出在其最小和最大传播时间之间被视为“未知”,但仿真无论如何都是有效的,这是一个很好的指示,设计是健壮的,但是有许多有用的设计无法构造成在这种模拟中工作(状态基本上可以保证演变成有效的组合,尽管不能保证哪一个)。尽管如此,这可能是一个有趣的探索途径,因为即使在“飞溅模式”VM中,也可以编写许多程序的大部分内容以正常工作。

答案 4 :(得分:1)

多线程程序中的大量崩溃与多线程本身(或相关的资源争用)无关。

答案 5 :(得分:0)

  

通常情况下,多线程程序是非确定性的,这意味着如果它崩溃,则几乎不可能重新创建导致该条件的错误。

我完全不同意这一点,确定多线程程序是不确定的,但是单螺​​纹程序也是如此,考虑到用户输入,消息泵,鼠标/键盘处理以及许多其他因素。多线程程序通常会使重现错误变得更加困难,但绝对不是不可能的。无论出于何种原因,程序执行并不是完全随机的,有某种可重复性(但不是可预测性),我通常可以在我的应用程序中快速重现多线程错误,但随后我的应用程序中有大量详细的日志记录,最终用户的行为。

顺便说一句,如果你遇到崩溃,你也不能通过调用堆栈信息获得崩溃日志吗?这将极大地有助于调试过程。

答案 6 :(得分:0)

我认为这不切实际。为了强制执行特定的线程交错,我们需要在共享变量上放置锁,强制线程以特定的顺序访问它们。这会导致严重的性能下降。

重放并发错误通常由记录和重放系统处理。由于记录如此大量的信息也会降低性能,最近的系统会进行部分记录,然后使用SMT求解完成线程交织。我相信这种类型系统的最新进展是Symbiosis(今年发布的PLDI会议)。 Tou可以在此URL中找到开源实现:

http://www.gsd.inesc-id.pt/~nmachado/software/Symbiosis_Tutorial.html

答案 7 :(得分:0)

这实际上是当今许多系统的有效要求,这些系统想要并行执行任务,但又不时需要一些确定性。

例如,一家移动公司希望并行处理多个用户的订阅事件,但希望一次执行一个用户的事件。

一种解决方案当然是编写所有内容以在单个线程上执行。另一种解决方案是确定性线程。我用 Java 编写了一个简单的库,可用于实现我在上面的示例中描述的行为。看看这个 - https://github.com/mukulbansal93/deterministic-threading

现在,话虽如此,CPU 给线程或进程的实际分配掌握在操作系统手中。因此,每次运行同一程序时,线程可能会以不同的顺序获得 CPU 周期。因此,您无法按照为线程分配 CPU 周期的顺序来实现确定性。但是,通过在线程之间有效地委派任务,将顺序任务分配给单个线程,您可以在整个任务执行中实现确定性。

另外,回答您关于模拟碰撞的问题。所有现代 CPU 调度算法都免于饥饿。因此,每个线程都必然会获得有保证的 CPU 周期。现在,您的崩溃可能是由于在单个 CPU 上执行特定线程序列造成的。无法重新运行相同的执行顺序或相同的 CPU 周期分配顺序。但是,如果您运行代码的次数足够多,现代 CPU 调度算法无饥饿和墨菲定律的结合将帮助您模拟错误。

PS,enough times的定义比较模糊,取决于整个程序所需的执行周期、线程数等很多因素。从数学上讲,这是一种粗略的计算模拟概率的方法相同的执行顺序导致的相同错误在单个处理器上是-

1/Number of ways to execute all atomic operations of all defined threads

例如,具有 2 个线程和 2 个原子指令的程序可以在单个处理器上以 4 种不同的方式分配 CPU 周期。所以概率是1/4。