C++ 线程在调用 `join()` 后仍然可以连接

C++ thread still joinable after calling `join()`

我有一段代码模拟了每个提供者和消费者都是一个线程的provider/consumer场景。我已将每个消费者与一个提供者配对,消费者将等到其提供者完成(通过在提供者线程上调用 join()),然后再执行。代码如下:

std::vector<std::thread> threads;
const uint32_t num_pairs = 3;

auto provider = [&](uint32_t idx) {
  /* produce resources and put them in a global container */
};

auto consumer = [&](uint32_t idx) {
  /* consumer i is paired with provider (i-num_pairs) */
  uint32_t provider_idx = idx - num_pairs;
  threads[provider_idx].join();
  assert(threads[provider_idx].joinable() == false);

  /* access the resources */
};

for (uint32_t i = 0; i < 2 * num_pairs; i++) {
  if (i < num_pairs) {
    /* 0, 1, 2 are providers */
    threads.emplace_back(provider, i);
  } else {
    /* 3, 4, 5 are consumers */
    threads.emplace_back(consumer, i);
  }
}

/* join the consumer threads later */

大多数时候它工作正常,但有时 consumer 中的断言会失败,并且提供者线程在加入后仍然可以加入。实施不正确还是有什么我不知道发生的事情?请帮助并提前致谢!

矢量 threads 随着您将线程推入其中而增长,很有可能某些线程会在您完成添加所有线程之前开始执行。当向量容量增加时,所有迭代器和对它的引用都变得无效。这意味着在 threads[provider_idx] 中,returned 引用可能在 [] 运算符的 return 和线程方法的执行之间无效。由于这是未定义的行为,因此您观察到 joinjoinable 的不当行为并不意外。

在创建线程之前保留向量的大小应该可以解决问题:

threads.reserve(2 * num_pairs);