【问题标题】:How to invoke member function safely when inheriting std::thread继承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 子类化。

标签: c++ multithreading


【解决方案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) : MyThreadData{a}, _thread([this] {run();}) {}
    
        void run()
        {
           // thread code here
        };
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 2011-03-04
      相关资源
      最近更新 更多