7

我正在使用此代码测试 c++11 线程,但是在创建线程时,我遇到错误no matching function for call to 'std::thread::thread()'

这就像我给 std::thread ctr 的函数有问题,但我不明白它是怎么错的。它不完整,但在我看来是正确的:

标题:

#ifndef CONNECTION_H
#define CONNECTION_H

#include <thread>
#include <mysql++.h>

class Connection
{
public:
    Connection(std::string mysqlUser, std::string mysqlPassword);
    ~Connection();

private:
    std::string mysqlUser;
    std::string mysqlPassword;
    std::string mysqlIP;
    int mysqlPort;

    mysqlpp::Connection mysqlConnection;
    std::thread connectionThread;

    void threadLoop();
};

#endif // CONNECTION_H

资源:

#include "connection.h"

Connection::Connection(std::string mysqlUser, std::string mysqlPassword)
{
    this->mysqlUser     = mysqlUser;
    this->mysqlPassword = mysqlPassword;
    this->mysqlIP       = "localhost";    //default
    this->mysqlPort     = 3306;           //default

    //Launch thread
    std::thread connectionThread(threadLoop);

}

Connection::~Connection(){
    mysqlConnection.disconnect();
}

void Connection::threadLoop(){
    //Connect to mySQL database
    mysqlConnection = new mysqlpp::Connection(false);

    if(mysqlConnection.connect(NULL, mysqlIP.c_str(), mysqlUser.c_str(), mysqlPassword.c_str(), mysqlPort)){
        std::string consulta = "SELECT * FROM 'Coordinates'";
        mysqlpp::Query query = mysqlConnection.query(consulta);
        mysqlpp::StoreQueryResult res = query.store();
        query.reset();

    }

    while(true){
        // Stuff
    }
}
4

3 回答 3

10

问题是这threadLoop是一个成员函数,但没有对象可以应用它。只是猜测:

std::thread connectionThread(&Connection::threadLoop, this);

但这只是句法问题。还有一个逻辑问题:该行创建了一个类型的本地对象,该对象std::thread在函数返回时消失。它的析构函数将调用std::terminate(),因为线程尚未加入。最有可能的是,这应该为connectionThread成员附加一个线程。要做到这一点:

std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);
于 2012-09-27T15:34:13.220 回答
5

您的代码有两个问题:

  1. 您正在向std::thread构造函数提供不完整的信息
  2. std::thread在它与主线程连接之前,您正在破坏它。

对于第一个问题,正如Pete Becker 所建议的那样,您需要提供将在其上调用函数的对象,因为 for 的构造函数std::thread没有其他方法可以知道它。假设你想在你正在构造threadLoop()Connection对象上调用函数,你可以这样做:

//Launch thread
std::thread connectionThread(threadLoop, this);

在内部,构造函数将调用this->threadLoop()(它接收this的参数在哪里,当然不是它本身)。你会没事的。Connection*std::thread

第二个问题是 yourstd::thread在启动后立即被销毁,而没有将其加入主线程:这将调用terminate(),这不是一件好事。皮特再一次提出了一个不错的选择。将上面的代码替换为:

// Launch thread
std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);

这段代码之前的情况如下:

  • 你有一个微不足道的std::thread对象,connectionThread它并不真正代表一个线程

执行第一行代码后:

  • 你还有connectionThread
  • 您还有一个由std::threadobject表示的活动线程thr,它将在构造函数的末尾被销毁Connection,从而导致调用,terminate()因为它从未加入到主线程中。

幸运的是,第二行代码提供了帮助。执行后:

  • 您有一个微不足道std::thread的 , thr,可以安全地销毁它,因为它不代表真正的线程(因此它不可连接)
  • 您有一个由 表示的活动线程connectionThread,只要该Connection对象存在,该对象就不会被销毁。

现在,问题是你想connectionThread在主线程被销毁之前加入它,但你也想避免阻塞主线程。进行此连接的正确时间是可能的最晚时间:connectionThread即将被销毁的时间。这发生在Connection. 所以我们将在这个析构函数中添加一行,这样:

Connection::~Connection(){
  mysqlConnection.disconnect();
  connectionThread.join(); // Now connectionThread can be safely destroyed
}

此外,这是最安全的呼叫地点join(),因为它确保您永远不会破坏未加入的connectionThread. 这是行动中的 RAII;如果您不熟悉 RAII(或 RIIA,有时称为)的概念,您可以在 Web 上找到很多关于这个非常重要的概念的信息,包括这个站点。

所有这些放在一起:创建一个Connection对象将创建一个新线程;在这个线程中,将建立一个新的数据库连接并执行一个查询,而主线程保持空闲用于任何其他用途(例如,管理 GUI)。当Connection对象最终被销毁时,主线程将等待附加线程完成(如果需要),然后继续正常执行。我希望这是你想用你的代码完成的。

于 2012-09-28T10:21:44.837 回答
2

正如您可能从cppreference中看到的那样,std::thread的构造函数期望某种形式的函数;您可以通过std::bind. 为了执行一个非静态成员函数,您应该使用std::mem_fn它与应该调用它的对象一起传递它。

于 2012-09-27T15:19:42.343 回答