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

时间:2015-03-28 02:42:50

标签: c printf openmp

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

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++;
}

简而言之,我正在使用Jacobi迭代方法求解Ax = b。我的问题是,在printf()语句取消注释的情况下,norm_of_error趋于零,而while循环结束。但是,通过简单地评论printf()声明,这不会发生。任何人都可以给我一个提示,为什么printf()声明有任何影响?我猜这个问题与omp_get_thread_num()的调用有关,但我不明白为什么会有所不同。

编辑:我将printf()语句更改为printf("hi\n");,代码正常运行。评论出来,代码不起作用。

3 个答案:

答案 0 :(得分:5)

printf()语句一起使用但在删除时失败的代码通常是某些无效操作的标志,这些操作会影响某个程序中的内存(例如,从数组的末尾掉下来,解除引用{{ 1}}等。行为不当的代码可能完全在程序的其他部分(例如,不在包含NULL语句的函数内)

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

原因是额外printf("Hi\n")的存在实际上影响了整个程序的内存布局。因此,违规代码(可能在程序中某些完全不相关的部分)仍会覆盖内存,但结果会发生变化(例如,覆盖某些数据,允许程序更改,而不是导致操作系统终止的某些内存区域)该计划)。

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

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

答案 1 :(得分:2)

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

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

printf到位的情况下,您的程序不会将数据保存在寄存器中 - 也许它不能以这种方式使用寄存器,或者它无法确定函数调用是否无法执行更改数据(当然,它只是printf,但它可能不是特殊的,即使它是,编译器更好地找到可能允许printf更改数据的漏洞) - 因此它在调用printf之后重新读取内存中的数据,从而查看在其他线程中进行的任何先前更改。

printf可能改变的另一件事是时间:与计算相比,I / O语句非常慢,并且I / O库中可能发生了一些的同步量;你的print可能会成为阻止竞争条件发生的伪障碍。

答案 2 :(得分:1)

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

C FAQ的部分位于strange problems

  

comp.lang.c常见问题列表·问题16.5

     

问:这个程序在一台机器上完美运行,但我在另一台机器上得到了奇怪的结果。更奇怪的是,添加或删除调试打印输出会改变症状......

     答:很多事情都可能出错;这里有一些比较常见的事情要检查:

     
      
  • 未初始化的局部变量[脚注](另见问题7.1)
  •   
  • 整数溢出,特别是在16位机器上,特别是在执行像* b / c这样的事情时的中间结果(参见问题3.14)
  •   
  • 未定义的评估顺序(参见问题3.1至3.4)
  •   
  • 省略了外部函数的声明,特别是那些返回int以外的函数,或者有``narrow''或变量参数的函数(参见问题1.25,11.3,14.2和15.1)
  •   
  • 取消引用空指针(参见第5节)
  •   
  • 不正确的malloc /免费使用:假设malloc的内存包含0,假设释放存储持续存在,释放两次,破坏malloc竞技场(另见问题7.19和7.20)
  •   
  • 一般指针问题(另见问题16.7和16.8)
  •   
  • printf格式与参数不匹配,尤其是尝试使用%d打印长整数(参见问题12.7和12.9)
  •   
  • 尝试分配比unsigned int更多的内存可以计算,特别是在内存有限的机器上(参见问题7.16和19.23)
  •   
  • 数组边界问题,特别是小的临时缓冲区,可能用于使用sprintf构建字符串[脚注](另见问题7.1,12.21和19.28)
  •   
  • 关于typedef映射的无效假设,尤其是size_t(参见问题7.15)
  •   
  • 浮点问题(见问题14.1和14.4a)
  •   
  • 您认为巧妙地利用您认为为特定系统生成代码的方式
  •   
     

正确使用函数原型可以捕获其中的几个问题;皮棉会抓到几个。另见问题16.3,16.4和18.4。