Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 std::thread giving error: no matching function to call std::thread::thread

I'm testing c++11 threads with this code, but when creating the thread, I'm having the error no matching function for call to 'std::thread::thread()'.

It's like if there was something wrong with the function I'm giving to std::thread ctr, but I don't see how it's wrong. It is incompleted, but it looks right to me:

Header:

#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

Source:

#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
    }
}
like image 553
Roman Rdgz Avatar asked Sep 27 '12 14:09

Roman Rdgz


2 Answers

The problem is that threadLoop is a member function, but there is no object for it to be applied to. Just guessing:

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

But that's just the syntactic issue; there's a logic problem, too: that line creates a local object of type std::thread that goes away when the function returns. Its destructor will call std::terminate() because the thread has not been joined. Most likely, this was supposed to attach a thread to the connectionThread member. To do that:

std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);
like image 84
Pete Becker Avatar answered Sep 21 '22 01:09

Pete Becker


Your code has two problems:

  1. You are providing incomplete information to the std::thread constructor
  2. You are destroying the std::thread before it is joined with the main thread.

For the first problem, as Pete Becker suggests, you need to provide the object on which the function will be called, because the constructor for std::thread has no other way to know it. Assuming that you want to call function threadLoop() on the Connection object you are constructing, you can do this:

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

Internally, the constructor will call this->threadLoop() (where this is the Connection* parameter it received, not the std::thread itself, of course). And you will be fine.

The second problem is that your std::thread is destroyed immediately after starting, without having joined it to the main thread: this will call terminate(), which is not a good thing. Once again, Pete suggests a good alternative. Replace the above code with this:

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

The situation before this code is as follows:

  • You have a trivial std::thread object, connectionThread, which does not really represent a thread

After executing the first line of code:

  • You still have connectionThread
  • You also have a live thread represented by the std::thread object thr, which will be destroyed at the end of the Connection constructor, causing a call to terminate() because it is never joined to the main thread.

Fortunately, the second line of code comes to the rescue. After executing it:

  • You have a trivial std::thread, thr, which can be safely destroyed because it does not represent a real thread (so it is not joinable)
  • You have a live thread represented by connectionThread, an object that will not be destroyed as long as the Connection object exists.

Now, the problem is that you want to join connectionThread to the main thread before it is destroyed, but you also want to avoid blocking the main thread. The right time to do this join is the latest possible time: when connectionThread is about to be destroyed. And this happens at the destructor of Connection. So we'll add a line to this destructor, this way:

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

Besides, this is the safest place to call join(), because it ensures that you will never destroy an unjoined connectionThread. This is RAII in action; if you are not familiar with the concept of RAII (or RIIA, as it is sometimes called), you can find a lot of information about this very important concept in the web, including this site.

All this put together: creating a Connection object will create a new thread; in this thread, a new database connection will be established and a query will be executed, while the main thread remains free for whatever other use (for instance, managing the GUI). When the Connection object is finally destroyed, the main thread will wait for the additional thread to finish (if necessary) and then normal execution will continue. I hope this is what you wanted to accomplish with your code.

like image 27
Gorpik Avatar answered Sep 23 '22 01:09

Gorpik