【问题标题】:Data exchange between threads线程间数据交换
【发布时间】:2017-08-11 02:07:55
【问题描述】:

我尝试编写一个物理模拟程序。我使用两个线程,一个用于计算,一个用于 gui。为了在它们之间交换数据,我使用了一个结构

struct sim_data {  
     int running;  
     int steps;  
    int progress;  
 ...  
};

并将其包含在不同的线程中

void *sim(void *args) {  
    struct sim_data *my_data;  
    my_data=(struct sim_data *)args;  
    ...  
}

设置值时

my_data->progress=1000;

数据在同一个线程中可用,但在第二个线程中不可靠。当启动程序在第二个线程中读取不同的值然后在第一个线程中写入时,我猜想有 10% 的机会。虽然数据是循环写入的,但我认为这不是时间问题。

我觉得这很奇怪。猜猜出了什么问题?

【问题讨论】:

  • 更准确地说,是同步问题(数据竞争)。您是否使用了适当的同步原语(互斥体、信号量...)?
  • 乍一看,这听起来像是一个竞争条件
  • 多线程编程真的很难。您不只是随便“同时运行两件事”。您必须非常仔细地考虑同步您的代码,并且这样做的结果必须在处理线程间通信的代码中可见。
  • @KerrekSB 权力越大,责任越大。 :)
  • @Scheddi:有一个相当不错的关于多线程的常见问题解答/Wiki:stackoverflow.com/questions/2118090/…。 @KlasLindbäck:但线程共享一个结构,其中一个成员running 看起来像一个标志。您根本不能使用volatile 来保证对标志的读/写顺序与结构中任何其他成员的读/写完全有任何关系。

标签: c++ multithreading


【解决方案1】:

C++11 规范将数据争用情况声明为任何时候一个线程写入某个位置而第二个线程可以读取或写入该位置。它声明当这种情况发生时你会得到未定义的行为。在您的情况下,一个线程正在写入 my_data->progress 而另一个线程正在读取它。

解决方案是使用同步,例如原子整数或锁定。

C++ 编译器进行了令人印象深刻的优化,使您的单线程程序运行得更快。例如,它可能证明,在单线程世界中,没有办法看到 1000 的值,干脆选择不打印。

还有更多合法的丑陋案件。如果编译器知道您想要存储 1000,它可能会选择根本不存储任何内容,而是使用该内存作为空间以将临时结果“溢出”到其中,而不是分配更多空间,然后最终存储 1000。期间同时,您可以读取任意值。

关于这个问题的幽默观点:http://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong

【讨论】:

    【解决方案2】:

    最简单的解决方案:

    struct sim_data {  
         int running;  
         int steps;  
         atomic<int> progress;  //this will guarantee the data are coherent between two threads
     ...  
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-08
      • 2020-02-23
      • 2011-09-15
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      相关资源
      最近更新 更多