std::使用类成员函数创建线程 - 最佳实践

std::thread creation with class member function - best practice

本文关键字:线程 最佳 创建 函数 成员 std      更新时间:2023-10-16

假设我们有一些类SomeAlgorithm,它已经用一堆数据和其他变量初始化了。我们现在想使用它的成员函数execute开始计算。让我们创建一个std::thread并使用主线程join它。

#include <thread>
#include <memory>
class SomeAlgorithm {
public:
void execute();
private:
// variables, eg. std::vector<int> data
};
int main() {
// (1)
{
SomeAlgorithm a1;
std::thread t1(&SomeAlgorithm::execute, &a1);
t1.join();
}
// (2)
{
SomeAlgorithm* a2 = new SomeAlgorithm();
std::thread t2(&SomeAlgorithm::execute, a2);
t2.join();
delete a2;
}
// (3)
{
std::unique_ptr<SomeAlgorithm> a3(new SomeAlgorithm());
std::thread t3(&SomeAlgorithm::execute, a3.get());
t3.join();
}
}

创建此类线程的首选方法是什么?是否有任何最佳实践? 在内存使用方面,确保释放分配的内存的最节省方法是什么?

切勿使用 (2(。这与线程无关。切勿使用显式new。智能指针(如果您需要拥有指针(。

至于(3(在你的例子中,你不需要指针。如果线程超出对象的作用域,则需要,例如:

std::thread t3;
{
auto a3 = std::make_unique<SomeAlgorithm>();
t3 = std::thread{&SomeAlgorithm::execute, std::move(a3)};
}
t3.join();

您的代码也存在一些问题。使用make_unique.有一些微妙的错误可以在没有它的情况下蔓延。正如我所说,永远不要使用明确的新。但最重要的是,不要使用get()因为它会使智能指针的整个点无效。

至于(1(我个人更喜欢:

// (1)
{
SomeAlgorithm a1;
std::thread t1{[&]{ a1.execute(); }};
t1.join();
}

通常(至少对我来说(它是(1(的形式:

{
SomeAlgorithm a1;
std::thread t1([&a1]() { a1.execute(); });
t1.join();
}

(3( 仅在您确实想从主线程中断开对象时使用。例如(从 C++14 开始(:

{
auto a3 = std::make_unique<SomeAlgorithm>();
std::thread t3([a{move(a3)}] { a->execute(); });
t3.join();
}

它可能会更清楚地显示您的意图(如果您不关心主线程中的实际结果(,但它的效率较低,主要是因为跨线程堆分配/释放。

(2( 只是一种已弃用(自 C++11 起(的执行方式 (3(。