c ++类方法线程

时间:2016-09-08 12:12:51

标签: c++ multithreading oop methods

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

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

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'初始化':无法转换为' void'到' std :: thread'

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

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

我不明白的是,这种方法并不仅仅使用泛型函数的类实例。如何将其链接到特定实例?我需要它,所以它可以读取变量的值。

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

(&SystemManager::runningAlgorithm)

第三是有更好的方法吗?你有什么想法吗?

提前谢谢。

4 个答案:

答案 0 :(得分: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 :(得分:1)

operator()的构造函数接受仿函数,并可选择接受它的参数。仿函数就是任何可以被称为"使用std::thread tRunning(&SystemManager::runningAlgorithm, SystemManager());

然后它启动一个线程,在该线程内部调用你的函子。

SystemManager::runningAlgorithm

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

runningAlgorithm从类SystemManager返回成员函数std::thread tRunning([]{ SystemManager().runningAlgorithm(); }); 的地址。

在现代C ++中,这个代码可以用lambda简化(即更易读):

A

答案 2 :(得分:1)

该行

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();
    

答案 3 :(得分:1)

嗯......我想你在进行多线程之前需要学习一些c ++的基本概念。

然而......在你的代码中,

    thread tRunning = SM->runningAlgorithm();

尝试将函数的结果(即void ...)放在thread类型的变量中......非常可能是正确的。

相反,你的第二个代码有两个参数:

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();
}

我仍然认为你应该首先习惯潜在的概念,否则将很难继续。