包含 std::threads 的元素向量

Vector of elements containing std::threads

本文关键字:元素 向量 threads std 包含      更新时间:2023-10-16

我有一个类Tester包含一个std:thread对象和一个Testerstd::vector。我知道我无法复制线程,所以push_back是不可能的,但是为什么emplace_back不起作用?代码中的副本在哪里?

#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <unistd.h>
class Tester
{
public:
Tester(std::function<void(void)> func) : 
th(func)
{
}
~Tester()
{
th.join()
}
private:
std::thread th;
};
std::vector<Tester> testers;
void InnerHelloWorld()
{
std::cout << "Hello from the inner word!n";
}
int main() {
std::cout << "Hello World!n";
for(size_t i = 0 ; i < 4 ; i++)
{
testers.emplace_back(InnerHelloWorld);
}
sleep(1);
return 0;
}

代码中有几个小问题

您错过了以下项的尾随分号:

th.join()

但重要的是,你需要给你的类一个移动构造函数 - 默认的很好:

Tester(Tester&&) = default;

这是必需的,因为当向量调整自身大小时,它们需要移动或复制其元素。通常会为您创建一个移动构造函数,但在您的情况下,使用自定义析构函数会抑制它。看这里。

这将允许代码编译,但随后会在运行时引发异常。这是因为您有时会从移自Testers中析构,这会在移自线程上调用 join。幸运的是,这是一个简单的解决方法:

~Tester()
{
if(th.joinable())
th.join();
}

完整工作代码:

#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <unistd.h>
class Tester
{
public:
Tester(std::function<void(void)> func) : 
th(func)
{
}
~Tester()
{
if(th.joinable())
th.join();
}
Tester(Tester&&) = default;
private:
std::thread th;
};
std::vector<Tester> testers;
void InnerHelloWorld()
{
std::cout << "Hello from the inner word!n";
}
int main() {
std::cout << "Hello World!n";
for(size_t i = 0 ; i < 4 ; i++)
{
testers.emplace_back(InnerHelloWorld);
}
sleep(1);
return 0;
}

你需要为你的类定义移动构造函数,以便它变得MoveInsertable并满足emplace方法的要求:

Tester(Tester && other) : 
th(::std::move(other.th))
{
}

修复缺少移动构造函数后会出现的另一个问题是尝试加入不可连接的线程,因为实际线程可能已被移动到另一个对象中。所以你需要添加一个相应的检查:

~Tester()
{
if(th.joinable())
{
th.join();
}
}