为什么在pragma omp critical之后多次调用printf会产生乱码输出?

时间:2017-08-05 20:12:28

标签: c++ c openmp

我有两个程序产生多个线程并将hello <TID> world <TID>打印到stdout。 第一个将它打印在一个函数中:

#include <omp.h>                                                
#include <stdio.h>                                               
int main() {                               
#pragma omp parallel                       
  {                                        
    int ID = omp_get_thread_num();         
#pragma omp critical                                  
    printf("hello  %d world %d\n", ID, ID);                                  
  }      
  return 0;                                  
}    

二分之二:

#include <omp.h>                                                  
#include <stdio.h>                                           
int main() {                               
#pragma omp parallel                       
  {                                        
    int ID = omp_get_thread_num();         
#pragma omp critical                       
    printf("hello  %d", ID);             
    printf("world %d\n", ID);                                                
  }  
  return 0;                                      
}      

程序只需调用printf(),输出就不会出现乱码。 但是,对于第二个程序,两次调用printf(),输出会出现乱码。 对于第二个程序,从来没有干扰字符串序列;从来没有类似hhhhellloohello...的东西。然而,不同的输出字符串之间存在混淆;一种可能性的排列:

hello  27hello  62hello  52hello  50hello  10world 62...

作为一个例子。

我认为#pragma omp critical会在pragma之后断言互斥,直到并行块结束。但事实似乎并非如此。 #pragma omp critical仅适用于紧随其后的声明吗?

任何有关出现这种情况的见解都会很棒。 艾萨克

3 个答案:

答案 0 :(得分:4)

#pragma omp critical { printf("hello %d", ID); printf("world %d\n", ID); } 一样,#pragma omp critical仅限于下一行,除非您也将其设为块。

如果您不想使用交错输出,请使用另一组花括号:

$list = file_get_contents('http://example.com/list/json');
$items = json_decode($list, true);

答案 1 :(得分:3)

可能是因为POSIX要求单个I / O函数调用是线程安全的,但不需要在单独的函数调用之间进行锁定。该规范的相关部分隐藏在页面上:

规范的相关部分接近结尾:

  

所有引用(FILE *)对象的函数,除了名称以_unlocked结尾的对象外,其行为应该像在内部使用flockfile()funlockfile()一样获得所有权这些(FILE *)个对象。

这意味着,例如,printf()必须在输入时执行(相当于)flockfile(stdout),在退出时必须(等效于)funlockfile(stdout)

这与您在OMP代码中看到的完全一致。单个调用printf()的文本不与任何其他并发调用交错,但printf()调用的序列在线程之间交错。

答案 2 :(得分:0)

here,您可以看到应该由一个线程一次运行的代码应放入代码块中。

添加名称也是一个好主意,这样如果你使用多个这样的指令就不会发生冲突,