为什么这段代码多次输出相同的数字?

时间:2017-02-11 15:44:58

标签: c++ multithreading pthreads

多次运行以下代码会产生多次出现相同数字的输出。我不知道为什么会这样。

#include <iostream>
#include <pthread.h>

using namespace std;

const int NUM_THREADS = 5;

void* thread_entry(void *i){
   cout<<(long)i<<endl;
}

int main () {
  pthread_t threads[NUM_THREADS];

  long i;
  for(i=0;i<NUM_THREADS;i++){
    pthread_create(&threads[i],NULL,&thread_entry,(void *)i);
  }

  return 0;
}

使用g++ -std=c++11 main.cpp -lpthread进行编译。

输出:

$ ./a.out 
0
1
4
$ ./a.out 
014
14
23
$ ./a.out 
02
2
3

3 个答案:

答案 0 :(得分:2)

该计划的主要问题是:

  1. 从具有声明的返回类型
  2. 的函数的末尾掉落
  3. 没有加入主题
  4. 在没有同步的情况下从多个线程使用std :: cout
  5. 从技术上讲,

    3不是必需的(如果修复了1和2),因为默认情况下通过std :: cout输出是线程安全的,不是数据争用,而是输出可以交错。

    现在,问题的有趣部分

      

    相同的数字不止一次出现。我不确定为什么会这样。

    假设您正在使用Linux或类似的东西,当主函数存在时,它会执行exit,在GNU C运行时,它会执行__run_exit_handlers,然后调用_IO_cleanup }。 _IO_cleanup的工作是写出任何未写入的输出缓冲区。如果发生其他一个线程正在编写中,例如在write(2)系统调用中,_IO_cleanup将查看缓冲区状态并查看它& #39; s仍然&#34;完整&#34; (_IO_file_write线程中的write(2)会在从write(2)返回时更新缓冲区位置指示符。因此,根据清理,缓冲区尚未写入,并且它会在同一缓冲区上启动自己的self.ui.lblImageName.setText(data['image']) 系统调用。

答案 1 :(得分:1)

official docs在这里有正确的答案。真正的问题不是加入线程。我将其余的留在这里作为参考:

您应该以不可预测的顺序看到输出,但它不应该产生重复的值。通常,cout不是线程安全的:

从C ++ 14:27.2.3 [iostreams.threadsafety]

  

并发访问流对象(27.8,27.9),流缓冲区对象(27.6)或C库流(27.9.2)   除非另有说明,否则多线程可能会导致数据争用(1.10)(27.4)。 [注:数据竞赛   导致未定义的行为(1.10)。 - 结束说明]

然而,27.4给出了在这种情况下适用的例外:

  

FILEs,同步访问同步(27.5.3.4)标准iostream对象的格式化和未格式化 -   不得产生put(27.7.2.1)和输出(27.7.3.1)函数或多个线程的标准C流   在数据竞赛中(1.10)。 [注意:用户仍必须同步这些对象和流的并发使用   多个线程,如果他们希望避免交错字符。 - 结束说明]

由于'relabel_configs' => [ { 'source_labels' => '[__meta_consul_node]', 'regex' => '^(.*)$', 'target_label' => 'instance', 'replacement' => '$1', }, { 'source_labels' => '[__meta_consul_service]', 'regex' => '^(.*)$', 'target_label' => 'job', 'replacement' => '$1', } ], 已同步,因此应该是线程安全的。

答案 2 :(得分:0)

在多线程中,无法保证线程中的代码将在另一个线程中的代码之前或之后运行而没有任何同步机制。

你有一个主线程和主线程创建的其他线程,你不能指望数字&#39; i&#39; 主线程的循环增加之前不会是