std::thread 的奇怪 `joinable()` 行为
Strange `joinable()` behavior with std::thread
我正在尝试实现一个线程列表,其中一个线程通过 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
在前一个线程上,以便等待它完成。但是我收到错误 22s(无效参数),根据文档,这意味着 joinable()
在某些情况下是错误的。
有时执行确实会通过所有线程,但随后会在 ~thread
中抛出异常,这会导致程序在退出前崩溃。
我在这里做错了什么?文档对此非常直接,所以我不确定我遗漏了什么
编辑:我标记为正确的答案确实指出了代码的问题,但我选择的解决方案是使用 std::list
而不是 std::vector
workers.emplace_back(&f2, i, std::ref(workers.back()));
这会导致 UB,因为您将指针传递给工作数据,然后增加其大小,这可能会重新分配其所有成员,从而导致引用无效。
我正在尝试实现一个线程列表,其中一个线程通过 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
在前一个线程上,以便等待它完成。但是我收到错误 22s(无效参数),根据文档,这意味着 joinable()
在某些情况下是错误的。
有时执行确实会通过所有线程,但随后会在 ~thread
中抛出异常,这会导致程序在退出前崩溃。
我在这里做错了什么?文档对此非常直接,所以我不确定我遗漏了什么
编辑:我标记为正确的答案确实指出了代码的问题,但我选择的解决方案是使用 std::list
而不是 std::vector
workers.emplace_back(&f2, i, std::ref(workers.back()));
这会导致 UB,因为您将指针传递给工作数据,然后增加其大小,这可能会重新分配其所有成员,从而导致引用无效。