【问题标题】:C++ async segment faultC++ 异步段错误
【发布时间】:2016-04-05 18:24:47
【问题描述】:

所以我写了下面这段代码。它有时会得到:

段错误::11

但有时不会。你能解释一下为什么吗?

我也对以下问题感到好奇。 一般来说,c++如何将线程分配给/c++何时执行launch::asynclaunch::defferred函数?如果是future<void>std::waitstd::get 有什么缺点吗?

std::future<void>r1, r2, r3, r4, ret;
//sometimes seg fault, sometimes pass
void f(int id, int t) {
    printf("call f(%d)\n", id);
    int ans=0;
    if (id == 3) {
      printf("wait 3\n");
      if (r1.valid()) r1.wait();
    }
    if (id == 4) {
      printf("wait 4\n");
      if (r1.valid()) r1.wait();
  }
  printf("start f(%d)\n",id);
  cnt[id]++;
  for (int i=1;i<=t;i++) {
      ans++;
  }
  printf("end f(%d)\n", id);
}

int main() {
  r3=async(f, 3, 1e8);
  r4=async(f, 4, 1);

  r1=async(f, 1, 1e8);
  r2=async(f, 2, 1e2);


  ret=async([&]() { r1.wait();r2.wait();r3.wait();r4.wait(); printf("cnt=%d,%d,%d,%d\n", cnt[1],cnt[2],cnt[3],cnt[4]); });

  return 0; 
}

【问题讨论】:

  • 声明cnt ?基于 1 的数组索引是一个值得关注的问题。
  • 什么是cnt?数数?为什么不叫它计数?这在任何地方都没有定义。如果有一些有意义的变量名会有所帮助。如果id==4 or 3,您正在引用r1。使用异步调用,不能保证 r1 已初始化,因此调用 r1.valid() 可能会导致 seg 错误。
  • @ChristopherSchneider 您可以在默认构造的未来调用valid()。它只返回false
  • 你需要发一个MCVE,有太多的可能性让别人猜到你的代码的其余部分

标签: c++ multithreading asynchronous future


【解决方案1】:

有时会得到:

段错误::11

但有时不会。你能解释一下为什么吗?

我假设 cnt 已正确声明,因此没有越界访问。如果是这种情况,那么我认为这里的问题是std::future 对象不是线程安全的,因此对r1.valid()r1.wait() 的调用与r1 的分配竞争发生在main 中。这样的数据竞争会导致未定义的行为。

看来你应该移动这条线

r1=async(f, 1, 1e8);

main 的开头。然后,对r1 的写入将在对r3r4 的调用std::async 之前进行排序。 std::async 的调用与f 的相应调用同步。因此,对r1 的写入发生在f 中对r1.wait 的调用之前。 future::wait 成员函数是const,所以两个线程可以同时调用它而不会争吵。

对于更复杂的情况,您可以使用std::packaged_task(如果需要,您可以先获取std::future,然后再启动)或std::promise

一般来说,c++如何分配线程到/c++何时执行launch::asynclaunch::defferred函数?

如果您问std::async 在您选择时如何选择使用哪种策略,答案是未指定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多