【发布时间】:2013-04-30 14:05:42
【问题描述】:
这是一段代码:
int somefunc() {
/* ... */
while ((pos = KMP_index(array, size, pattern, plen)) > -1) {
count++;
}
return count;
}
somefunc()在多个子进程中被调用,每个fork调用一次。
我的代码在 Linux x86_64 和 i386 上按预期编译和工作。但是当我在 Atom 上网本(Arch Linux i686)上运行它时,count 变量永远不会超过 2!
while (...) {
count++; //succesfully increments
}
return count; //it's maximum 2!
但是,如果我添加 printf() :
while (...) {
count++; //succesfully increments
printf("%d", anything);
}
return count; //value as expected
打印空字符或fflushing 标准输出在这里不起作用。我必须打印至少一个字符,然后变量才可以。它让我发疯。
有人可以告诉我,为什么我还要使用这种“解决方法”? 这可能是我的linux环境的问题吗? (没什么特别的,GCC 4.8,股票内核) 谢谢。
P.S 整个来源在这里 http://pastebin.com/4eEHMbKn 。 是的,这是一个家庭作业 :) 我需要创建一个类似 grep 的实用程序,在单独的进程中处理每个文件。
【问题讨论】:
-
闻起来像未定义的行为。无法从可见代码中分辨出哪里。
-
可能您的代码的某些部分正在影响函数的操作,而 printf 会更改执行时间,从而影响结果。它可以无线程工作吗?您在函数中访问了哪些非本地变量?一个线程更改某个此类 var 对任何其他线程有什么影响?
-
您可能需要将其标记为
volatile以避免编译器优化快捷方式。一般来说,在多个线程或进程中弄乱一个变量并不是一个好主意。如果您没有明确控制来自多个线程的同时访问,我不确定该行为是否已定义。 -
@ArtSwri,它确实可以无线程工作。唯一的非本地变量是参数:
int badgrep(const char *file, int size, const char *pattern, int plen)。有问题的 var 是在函数内创建和返回的,所以它完全是本地的(我认为?)。我还应该把它标记为易失性吗,@JimStewart? -
如果您使用线程,或单独的进程但共享内存,您可以使用原子内置函数:
__sync_fetch_and_add(&counter, 1)递增计数器,__sync_fetch_and_add(&counter, 0)读取它。但是,Mike Roll,我不认为是这样。非空printf()需要实际运行时间,因此很可能在KMP_index()函数中存在竞争条件,导致循环仅在原子上执行两次。您可以通过在正文中添加sched_yield()或usleep(1)调用来验证这一点(而不是printf()来改变时间):您应该得到相同的效果。