我在多进程程序中有一个错误。程序接收输入并立即产生输出,不涉及网络,并且没有任何时间参考。 导致此错误难以追踪的原因是它只发生有时。
如果我经常运行它,它会产生正确和错误的输出,没有可辨别的顺序或模式。
什么可能导致这种非确定性行为?那里有工具可以提供帮助吗?有可能存在未初始化的变量。我怎么找到那些?
编辑:问题已解决,感谢任何建议的人 种族条件。 我没想到它主要是因为我确信我的设计可以防止这种情况。问题是我使用'等待'而不是'waitpid',因此有时候,当某个过程足够幸运地在我期待之前完成时,事情的正确顺序就会疯狂。
答案 0 :(得分:5)
你说这是一个“多进程”程序 - 你能更具体一点吗?在你如何处理多个过程中,这可能是一个竞争条件。
如果您可以告诉我们有关流程如何互动的更多信息,我们可能会想出一些可能性。请注意,尽管Artem建议使用调试器本身很好,但您需要注意,引入调试器可能会很好地改变完全的情况 - 特别是在竞争条件方面。就个人而言,我很喜欢记录很多,但即使这样也可以巧妙地改变时间。
答案 1 :(得分:3)
调度程序!
基本上,当你有多个进程时,它们可以以他们想要的任何奇怪的顺序运行。如果这些进程共享一个他们都在读取和写入的资源(无论是文件或内存还是某种类型的IO设备),操作将会在各种奇怪的命令中交错。举个简单的例子,假设你有两个线程(它们是线程,因此它们共享内存),并且它们都试图增加一个全局变量x。
y = x + 1;
x = y
现在运行这些进程,但以这种方式交错代码
假设x = 1
P1:
y = x + 1
现在在P1中,对于本地和堆栈的变量y,y = 2
。然后调度程序进入并启动P2
P2:
y = x + 1
x = y
x仍然是1,因此已添加1,现在x = 2
然后P1结束
P1:
x = y
和x仍然是2!我们增加了两次x,但只获得了一次。而且因为我们不知道 将如何发生,所以它被称为非确定性行为。
好消息是,你偶然发现了系统编程中最棘手的问题之一,以及许多功能语言人员的主要战斗口号。
答案 2 :(得分:3)
您最有可能看到race condition,即不可预测,因此难以重现和调试不正确同步的线程或进程之间的交互。
这种情况下的非确定性源于进程/线程和内存访问调度。这是不可预测的,因为它受到大量外部因素的影响,包括网络流量和用户输入,这些因素不断导致中断,并在每次运行时导致程序线程中不同的实际执行顺序。
答案 3 :(得分:2)
它可能是很多东西,内存泄漏,关键部分访问,未封闭的资源,未关闭的连接等。只有一个工具可以帮助你 - 调试,或尝试检查你的算法,找到错误,或者如果你成功指出了有问题的部分,你可以在这里粘贴一个片段,我们会尽力帮助你。
答案 4 :(得分:2)
从基础知识开始...确保所有变量都具有默认值,并且在使用之前将所有动态内存清零(即使用calloc而不是malloc)。应该有一个编译器选项来标记这个(除非你使用一些模糊的编译器)。
如果这是c ++(我知道假设是'c'论坛),有时候对象创建和初始化滞后于变量赋值可能会让你感到困惑。例如,如果您的作用域由多个线程同时使用(如在单例或全局var中),则可能会导致问题:
if(!foo) Foo tmp = new Foo();
如果你有多个线程访问上面的内容,第一个线程会找到foo = null并启动对象创建和赋值然后产生。另一个线程进来并找到foo!= null,因此跳过该部分并开始使用foo。
答案 5 :(得分:1)
我们需要查看有关您的代码的详细信息,以便能够提供更准确的答案,但简而言之,当您拥有一个协调多个进程或多个线程的程序时,线程执行时的变量可以为您的应用程序添加不确定性。本质上,操作系统执行的调度可能导致进程和线程无序执行。根据您的环境和代码,操作系统执行的计划可能会导致截然不同的结果。您可以在谷歌上搜索有关多线程无序执行的更多信息,以获取更多信息;这是一个很大的话题。
答案 6 :(得分:0)
通过“多进程”你的意思是多线程?如果我们有两个执行此例程的线程
i = 1;
while(true)
{
printf(i++);
if(i > 4) i = 1;
}
通常我们希望输出类似于
112233441122334411223344
但实际上我们会看到像
这样的东西11232344112233441231423
这是因为每个线程都会以不同的速率使用CPU。 (调度时间表背后有很多复杂的东西,而且我太弱了,无法告诉你背后的技术内容。)可以说,从普通人的角度来看调度是非常随机的。
这是其他评论中提到的竞争条件的一个例子。