【问题标题】:c++ class method thread [duplicate]c ++类方法线程[重复]
【发布时间】:2017-01-16 08:47:12
【问题描述】:

我有一个类,它有一个需要连续运行但也能够接收用户输入的方法。所以我想我会使用线程单独运行该方法。

代码看起来像这样(只是主干):

class SystemManager
{
private:
    int command;
    bool commandAcK;

    bool running;

    //other vars

public:

    SystemManager()
    {
        //initialisation
    }

    void runningAlgorithm()
    {

        while (running)
        {
            if (commandAcK)
            {
                //solve command
            }

            //run algorithm
            //print results
        }

    }


    void readCmd()
    {

        cin >> command;
        commandAcK = true;

    }



};




int main()
{

    SystemManager *SM = new SystemManager;

    thread tRunning = SM->runningAlgorithm();


}

现在错误如下所示:

不存在合适的构造函数来将“void”转换为“std::thread

错误 C2440 'initializing':无法从 'void' 转换为 'std::thread'

我找到了一个新方法,它没有给我任何错误

std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager());    

我不明白的第一件事是这个方法不使用类的实例,只是使用泛型函数。如何将其链接到特定实例?我需要它,以便它可以读取变量的值。

其次SystemManager前面的"&"是做什么的?

(&SystemManager::runningAlgorithm)

第三,有没有更好的方法呢?你有什么想法吗?

提前谢谢你。

【问题讨论】:

    标签: c++ multithreading oop methods


    【解决方案1】:

    std::thread 的构造函数接受 functor,并且可以选择接受参数。函子是可以使用operator()“调用”的任何东西。

    然后它启动一个线程并在该线程内调用你的仿函数。

    std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager());  
    

    这将调用成员函数SystemManager::runningAlgorithm,传入唯一的参数thisSystemManager() 创建一个临时实例)。 请记住,成员函数始终接受this 作为第一个参数。

    &SystemManager::runningAlgorithm从类SystemManager返回成员函数runningAlgorithm的地址。

    在现代 C++ 中,此代码可以使用 lambda 进行简化(即更易读):

    std::thread tRunning([]{ SystemManager().runningAlgorithm(); });
    

    【讨论】:

      【解决方案2】:

      std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager()); 确实使用了您的类的实例。它使用的实例是SystemManager(),这是一个临时的并且只对线程可用。如果您需要共享实例,那么您需要自己创建一个实例并通过引用来传递它,例如

      SystemManager sys_manager;
      std::thread tRunning([&](){sys_manager.runningAlgorithm();});
      

      现在您的调用站点和线程具有相同的实例。

      还要注意commandcommandAck 需要通过某种同步来保护,因为您可以在读取时写入它们,从而导致data race 和随后的undefined behavior。使用 std::atmoic 应该适合你。

      【讨论】:

      • +1 用于同步,但为什么是 lambda?当您已经拥有所需的一切时,为什么还要建立一个闭包?
      • @marco6 我使用了 lambda,因为对我来说,这是一种将引用绑定到函数的简单方法。我不太记得如何使用 bind 或线程构造函数来做到这一点,但我知道这是可行的,所以这就是我所做的。我也认为它更能表达我想要发生的事情。
      • 当然!只有一件事:要记住,如果 sys_manager 超出范围而其他线程仍在运行,那将是一团糟……
      • @marco6 当然还有。如果需要保证,我会使用std::shared_ptr。确实,仅当 std::thread 超出范围时才需要它。如果不是,那么线程将在 sys_manger 被销毁之前结束并且您没有问题(感谢构造/销毁规则的范围和顺序)。
      • 我不会让初学者这样写 lambda([&][=] 可能很危险)。
      【解决方案3】:

      线

      thread tRunning = SM->runningAlgorithm(); 
      

      获取运行SM->runningAlgorithm()void)的结果,并尝试从中构造一个线程。但是,如果您查看the relevant constructor,您会发现它需要一个类似函数的参数(可能还有参数)。

      一种运行方式是通过 lambda 函数:

      thread tRunning(
          [SM](){SM->runningAlgorithm();});
      

      另外两点需要注意:

      1. 你应该在调用它的析构函数之前加入线程,在这种情况下:

        tRunning.join();
        
      2. 您有一个(短暂的)内存泄漏。为什么不直接在堆栈上创建它?

        SystemManager SM;
        
        thread tRunning(
            [&](){SM.runningAlgorithm();});
        
        tRunning.join();
        

      【讨论】:

        【解决方案4】:

        嗯...我猜你需要学习一些 c++ 的基本概念,然后再开始多线程。

        但是...在您的代码中,

            thread tRunning = SM->runningAlgorithm();
        

        尝试将函数的 result(即 void...)放入 thread 类型的变量中...不太可能是对的。

        相反,您的第二个代码采用 2 个参数:

        std::thread tRunning(
                &SystemManager::runningAlgorithm, //a pointer to a method (a pointer to the code of your function, and that is why you use the "&", even though you could have left that out)
                SystemManager()); // An instance of the value, built on the stack.
        

        我请你对缺少“新”这个词(来自高级语言?)感到困惑,但这就是它在这里的工作方式:

        SystemManager sm = SystemManager(); // <- variable created on the stack, will be automatically destroyed when out of scope
        SystemManager *psm = new SystemManager(); // Created in the heap, while in the stack remains just a pointer to it. 
        //You will need to delete it when done with :
        delete psm;
        

        回答问题

        如何将其链接到特定实例?我需要它,以便它可以读取变量的值。

        你可以这样做:

        int main()
        {
        
            SystemManager SM; // = SystemManager(); // <- this is not needed
        
            std::thread tRunning(SystemManager::runningAlgorithm, SM);
            // Access SM as you need
        
            // REMEMBER TO CLOSE & JOIN THE THREAD!
            tRunning.join();
        }
        

        我仍然认为您应该首先习惯基本概念,否则将很难继续下去。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-11
          • 2011-07-06
          • 2010-12-21
          相关资源
          最近更新 更多