为什么插入 printf 语句会使我的函数正常工作?

Why does inserting a printf statement make my function work correctly?

这是我的代码的基本前提:

while(norm_of_error > tol){
  #pragma omp parallel for
  for(i = 1; i <= N*N; i++){
    //printf("thread id: %d\n",omp_get_thread_num());
      :
    int val = based on i
      :
    #pragma omp critical
    x[i-1] = val;
  }
  #pragma omp barrier
  iter++;
}

简而言之,我正在使用雅可比迭代法求解 Ax = b。我的问题是,在 printf() 语句未注释的情况下,norm_of_error 趋于零并且 while 循环结束。但是,通过简单地注释掉 printf() 语句,这不会发生。谁能给我一个提示,说明为什么 printf() 语句会产生任何影响?我猜这个问题与对 omp_get_thread_num() 的调用有关,但我不明白为什么这会产生任何影响。

编辑:我将 printf() 语句更改为 printf("hi\n"); 并且代码有效。注释掉,代码不起作用。

您尚未发布您的代码,因此我们无法确定,但这通常是因为您试图在线程之间共享数据而没有充分表明要共享数据。

删除printf后,您的程序正在将数据加载到寄存器中,当它再次需要数据时,它会记住寄存器中的值而不是再次从内存中获取它,因此它不会'查看您的其他线程可能做出的任何更改。

printf 就位后,您的程序不会将数据保存在寄存器中——也许它不能以这种方式使用寄存器,或者它无法确定函数调用无法更改数据(当然,它只是 printf,但它可能不是特例,即使是,编译器更善于发现可能允许 printf 更改数据的漏洞你是)——因此它在调用 printf 后从内存中重新读取数据,从而查看之前在其他线程中所做的任何更改。

printf 可以改变的另一件事是计时:I/O 语句与计算相比相当慢,并且可能有 一些 同步量发生在 I/O 图书馆内;您的 print 可能充当防止竞争条件发生的伪屏障。

代码与 printf() 语句一起工作,但在删除时失败,通常是一些无效操作的标志,影响了程序中某处的内存(例如,从数组的末尾脱落,取消引用NULL,等等)。行为不当的代码可能完全位于程序的其他部分(例如,不在包含 printf() 语句的函数内)

当有问题的 printf() 语句显然是无辜的,并且没有任何可能影响其他代码行为的副作用(例如 printf("Hi\n"))时,这种情况更有可能发生。

原因是额外 printf() 的存在确实会影响整个程序的内存布局。因此,有问题的代码(可能位于程序的某些完全不相关的部分)仍然会覆盖内存,但结果会发生变化(例如,覆盖允许程序更改的某些数据,而不是导致操作系统终止的某些内存区域程序)。

无论代码是否为多线程,都是如此。

如果没有完整的代码来说明问题(即其他人可以编译、构建的小示例,并且 运行 得到相同的症状),则不可能更具体。

请记住,C 和 C++ 是不同的语言

C FAQ has as section on strange problems:

comp.lang.c FAQ list · Question 16.5

Q: This program runs perfectly on one machine, but I get weird results on another. Stranger still, adding or removing a debugging printout changes the symptoms...

A: Lots of things could be going wrong; here are a few of the more common things to check:

  • uninitialized local variables [footnote] (see also question 7.1)
  • integer overflow, especially on 16-bit machines, especially of an intermediate result when doing things like a * b / c (see also question 3.14)
  • undefined evaluation order (see questions 3.1 through 3.4)
  • omitted declaration of external functions, especially those which return something other than int, or have ``narrow'' or variable arguments (see questions 1.25, 11.3, 14.2, and 15.1)
  • dereferenced null pointers (see section 5)
  • improper malloc/free use: assuming malloc'ed memory contains 0, assuming freed storage persists, freeing something twice, corrupting the malloc arena (see also questions 7.19 and 7.20)
  • pointer problems in general (see also questions 16.7 and 16.8)
  • mismatch between printf format and arguments, especially trying to print long ints using %d (see questions 12.7 and 12.9)
  • trying to allocate more memory than an unsigned int can count, especially on machines with limited memory (see also questions 7.16 and 19.23)
  • array bounds problems, especially of small, temporary buffers, perhaps used for constructing strings with sprintf [footnote] (see also questions 7.1, 12.21, and 19.28)
  • invalid assumptions about the mapping of typedefs, especially size_t (see question 7.15)
  • floating point problems (see questions 14.1 and 14.4a)
  • anything you thought was a clever exploitation of the way you believe code is generated for your specific system

Proper use of function prototypes can catch several of these problems; lint would catch several more. See also questions 16.3, 16.4, and 18.4.