c++类方法线程

c++ class method thread

本文关键字:线程 类方法 c++      更新时间:2023-10-16

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

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

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)

第三,有没有更好的方法?你有什么主意吗?

提前感谢。

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

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

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

还需要注意commandcommandAck需要某种同步保护,因为您可以在读取时对它们进行写操作,从而导致数据竞争和随后的未定义行为。使用std::atmoic应该适合您。

std::thread的构造函数接受函子,并可选地接受它的参数。函子是任何可以用operator()"调用"的对象。

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

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

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

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

在现代c++中,这段代码可以用lambda:

来简化(即使其更具可读性):
std::thread tRunning([]{ SystemManager().runningAlgorithm(); });

thread tRunning = SM->runningAlgorithm(); 

获取运行SM->runningAlgorithm() (void)的结果,并尝试以此构建一个线程。但是,如果查看相关的构造函数,就会发现它需要一个类似函数的实参(可能有实参)。

运行它的一种方法是通过lambda函数:

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

还有两点需要注意:

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

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

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

嗯…我想在使用多线程之前,你需要学习一些c++的基本概念。

然而

…在您的代码中,

    thread tRunning = SM->runningAlgorithm();

试图把结果的函数(这是void…)在线程类型的变量中…不太可能是对的。

相反,第二段代码接受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();
}

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