11

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

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

但是,如果您有用于线程调度的算法,并且如果您知道什么线程正在运行,那么多线程程序是否会变得“确定性”,例如,您将能够重现崩溃?

4

8 回答 8

12

了解算法实际上并不能让您预测什么时候会发生什么。程序或线程执行中发生的各种延迟取决于环境条件,例如:可用内存、交换、传入中断、其他繁忙任务等。

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

如果你想了解更多,http ://en.wikipedia.org/wiki/Process_calculus是非常有趣的阅读。

于 2010-09-30T12:18:29.357 回答
6

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

于 2010-09-30T12:15:33.443 回答
3

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

国际象棋就是一个例子。

于 2010-09-30T12:19:41.857 回答
3

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

于 2010-09-30T15:23:52.090 回答
0

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

于 2010-09-30T12:14:38.217 回答
0

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

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

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

于 2015-06-14T19:44:46.917 回答
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。

于 2021-04-18T07:13:24.037 回答
-1

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

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

顺便说一句,如果您遇到崩溃,您是否还可以获得带有调用堆栈信息的崩溃日志?这将极大地帮助调试过程。

于 2010-09-30T13:07:46.750 回答