Странное `joinable ()` поведение с std :: thread - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь реализовать список потоков, в которых один поток связывается с другим через std::thread::join, чтобы завершить его, пока не будут выполнены все задания.

#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
#include <sstream>
#include <stdio.h>

std::vector<std::thread> workers;

void f1(void)
{
  std::cout<<"begin f1"<<std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout<<"end f1"<<std::endl;
}

void f2(int sleep_for, std::thread & previous_thread)
{
  try
  {
    previous_thread.join();
    std::cout<<"begin f2"<<std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout<<"end f2"<<std::endl;
  }
  catch (const std::system_error& ex)
  {
    std::stringstream ss;
    ss << ex.code() << '\n';
    ss << ex.code().message() << '\n';
    ss << ex.what() << '\n';
    printf("%s",ss.str().c_str());
  }
}

int main(void)
{
  std::cout<<0<<std::endl;
  workers.emplace_back(&f1);
  for(int i=0;i<3;i++)
  {
    std::cout<<i+1<<std::endl;
    workers.emplace_back(&f2, i, std::ref(workers.back()));
  }
  workers.back().join();
  /*
  std::thread t(&f1);
  std::thread t1(&f2, 0, std::ref(t));
  std::thread t2(&f2, 1, std::ref(t1));                                                                                                                                                                                                        
  std::thread t3(&f2, 2, std::ref(t2));
  t3.join();
  */
  return 0;
}

В этом коде вы можете видеть Я раскручиваю 4 потока, и каждый поток после первого должен join в предыдущем потоке, поэтому он будет ждать его окончания sh. Однако я получаю сообщение об ошибке 22 (недопустимый аргумент), что в соответствии с документацией означает, что в некоторых случаях joinable() является ложным.

Иногда при выполнении все потоки выполняются, но в * 1009 выдается исключение * что заставляет программу взламывать sh непосредственно перед выходом.

Что я здесь не так делаю? Документы действительно просты в этом вопросе, поэтому я не уверен, что мне не хватает

Редактировать: ответ, который я пометил как правильный, указывает на проблему с кодом, но я выбрал решение использовать std::list вместо std::vector

1 Ответ

2 голосов
/ 02 апреля 2020

workers.emplace_back(&f2, i, std::ref(workers.back()));

Это приводит к UB, когда вы передаете указатель на рабочие данные, а затем увеличиваете его размер, что потенциально перераспределяет всех его членов, вызывая недействительность ссылки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...