继承std::thread时如何安全调用成员函数

Posted

技术标签:

【中文标题】继承std::thread时如何安全调用成员函数【英文标题】:How to invoke member function safely when inheriting std::thread 【发布时间】:2019-10-08 02:59:22 【问题描述】:

我的代码如下:

  class MyThread : public std::thread 
        int a_;

    public:
        MyThread(int a)
            : std::thread(&MyThread::run, this),
              a_(a)
         

        void run() 
            // use a_
        
    ;

我想拥有自己的线程类,它拥有 std::thread 提供的所有方法,所以我让 MyThread 类继承 std::thread。 在 MyThread 的构造函数中,我将其成员函数传递给 std::thread。编译没问题,但我担心在 std::thread 的构造函数中调用 run() 和初始化 a_ 之间存在竞争条件。

有没有办法让它安全?

【问题讨论】:

which has all the methods that std::thread provides 您具体指的是哪些方法?您无需继承即可访问公共成员函数。访问受保护的成员函数和变量可能是一种情况,但我不知道。 @TrickorTreat,join() 或 get_id() 等方法。我不想通过组合和适配 std::thread 对象在 MyThread 中再次添加这些接口,所以我直接将 std::thread 子类化。 【参考方案1】:

不要那样做。 “Has-a”(组合)比“is-a”(继承)有很多优势。

class MyThread

    std::thread _thread;
    int _a;
public:

    MyThread(int a) : _a(a)
    
        _thread = std::thread([this] run(););
    

    void run()
    
       // thread code here
    ;

    void join()
    
        _thread.join();
    
;

更好的方法是认识到线程和该线程上的操作是两个不同的对象:

class WorkerOperation

    int _a;
public:
   WorkerOperation(int a) :  _a(a)
   
   

   void run()
   
     // your code goes here
   
;

然后创建一个线程:

shared_ptr<WorkerOperation> spOp = make_shared<WorkerOperation>(42);
std::thread t = std::thread([spOp] spOp->run(););

如果你真的需要将操作和线程配对:

std::pair<WorkerOperation, std::thread> threadpair;
threadpair.first = spOp;
threadpair.second = std::move(t);

【讨论】:

【参考方案2】:

要修复错误,您可以编写:

    MyThread(int a)
        :a_(a)
     
        (std::thread&)(*this) = std::thread(&MyThread::run, this);
     

这样,线程以初始化的a_ 运行。

一般来说,我认为从 std::thread 继承并不是一个好主意。最好将其设为私有成员并运行它。否则,如果您允许他们公开将您的课程转换为 std::thread& ,用户可能会做一些奇怪的事情。就像执行与您预期不同的功能一样。

【讨论】:

好吧,这可能是添加 MyThread& operator=(std::thread&&) 覆盖后的解决方法。谢谢@alx23z【参考方案3】:

但我担心在 std::thread 的构造函数中调用 run() 和初始化 a_ 之间存在竞争条件。

是的,

您可以重新排序成员/基地:

struct MyThreadData

    int _a;
;

struct MyThread : MyThreadData, std::thread

public:
   explicit MyThread(int a) : MyThreadDataa, _thread([this] run();) 

    void run()
    
       // thread code here
    ;
;

【讨论】:

以上是关于继承std::thread时如何安全调用成员函数的主要内容,如果未能解决你的问题,请参考以下文章

无法将类成员函数传递给另一个函数(std::thread::thread)

使用成员函数启动线程

使用成员函数启动线程

C++ std::thread 无效使用 void 表达式

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

如何使用 std::thread C++ 生成多个调用相同函数的线程 [关闭]