C++ C++;11 std::thread给定错误:没有匹配的函数来调用std::thread::thread

C++ C++;11 std::thread给定错误:没有匹配的函数来调用std::thread::thread,c++,c++11,stdthread,C++,C++11,Stdthread,我正在用这段代码测试c++11线程,但是在创建线程时,出现了一个错误,调用“std::thread::thread()”时没有匹配的函数。 这就像我给std::thread ctr的函数有什么问题,但我看不出有什么问题。它是不完整的,但在我看来是正确的: 标题: #ifndef CONNECTION_H #define CONNECTION_H #include <thread> #include <mysql++.h> class Connection { publ

我正在用这段代码测试c++11线程,但是在创建线程时,出现了一个错误,调用“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

正如您可以从中看到的,
std::thread
的构造函数期望某种形式的函数;您可以通过传递一个自由函数、一个静态成员函数或其中的一个函数及其参数。为了执行非静态成员函数,您应该使用它与应该调用它的对象一起传递。

问题在于
threadLoop
是一个成员函数,但没有要应用它的对象。只是猜测:

std::thread connectionThread(&Connection::threadLoop, this);
但这只是句法问题;还有一个逻辑问题:该行创建了一个类型为
std::thread
的本地对象,该对象在函数返回时消失。它的析构函数将调用
std::terminate()
,因为线程尚未联接。最有可能的情况是,这会将线程附加到
connectionThread
成员。为此:

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

您的代码有两个问题:

  • 您向
    std::thread
    构造函数提供的信息不完整
  • 您正在销毁
    std::thread
    ,然后将其与主线程连接
  • 对于第一个问题,如,您需要提供调用函数的对象,因为
    std::thread
    的构造函数没有其他方法知道它。假设您希望对正在构造的
    连接
    对象调用函数
    threadLoop()
    ,则可以执行以下操作:

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

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

    // Launch thread
    std::thread thr(threadLoop, this);
    std::swap(thr, connectionThread);
    
    本规范之前的情况如下:

    • 您有一个普通的
      std::thread
      对象,
      connectionThread
      ,它实际上并不表示线程
    执行第一行代码后:

    • 您仍然有
      连接阅读
    • 您还有一个由
      std::thread
      对象
      thr
      表示的活动线程,它将在
      连接
      构造函数结束时被销毁,导致调用
      terminate()
      ,因为它从未连接到主线程
    幸运的是,第二行代码出现了。执行后:

    • 您有一个普通的
      std::thread
      thr
      ,可以安全地销毁它,因为它不代表一个真正的线程(因此它是不可连接的)
    • 您有一个由
      connectionThread
      表示的活动线程,只要
      Connection
      对象存在,该对象就不会被销毁
    现在的问题是,您希望在主线程被销毁之前将
    connectionThread
    连接到主线程,但也希望避免阻塞主线程。进行此连接的正确时间是最晚可能的时间:当
    connectionThread
    即将被销毁时。这发生在连接的析构函数处。我们将向这个析构函数添加一行,如下所示:

    Connection::~Connection(){
      mysqlConnection.disconnect();
      connectionThread.join(); // Now connectionThread can be safely destroyed
    }
    
    此外,这是调用
    join()
    最安全的地方,因为它可以确保您永远不会破坏未连接的
    连接。这是雷伊在行动;如果您不熟悉RAII(有时也被称为RIIA)的概念,您可以在web(包括本网站)上找到许多关于这个非常重要概念的信息


    所有这些加在一起:创建一个
    连接
    对象将创建一个新线程;在这个线程中,将建立一个新的数据库连接并执行一个查询,而主线程则可以自由地用于任何其他用途(例如,管理GUI)。当
    连接
    对象最终被销毁时,主线程将等待附加线程完成(如有必要),然后继续正常执行。我希望这就是您希望用代码实现的目标。

    请提供一个完整的、最少的示例程序。根据您的描述,它应该适合5-10行左右。请参阅。
    std::thread
    的构造函数不期望自由函数或至少静态成员函数吗?它怎么知道在哪个对象上调用
    Connection::threadLoop
    ?你在使用哪个编译器?@nicolamasatti:我想你应该把它变成一个答案。你在构造函数中声明了一个新的线程对象。我怀疑这是你的意图。这里不需要
    std::bind
    std::men\fn
    <代码>标准::线程的构造函数知道如何处理成员函数。问题是没有要应用成员函数的对象。我明白了。我手边没有标准,CPPFerence在这个问题上不是很清楚。CPPFerence很清楚,但它是错误的。对于TR1,我们发明了调用术语来描述
    bind
    function
    如何处理各种可调用类型,包括指向成员函数的指针(第二个参数必须是对象、对象引用或指向适当类型的对象的指针)<代码>标准::线程::线程(Fn&&,Args&&…
    使用相同的机制。@PeteBecker:我正在阅读标准的
    Connection::~Connection(){
      mysqlConnection.disconnect();
      connectionThread.join(); // Now connectionThread can be safely destroyed
    }