7

このコードで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

ソース:

#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

コードには2つの問題があります。

  1. std::threadコンストラクターに不完全な情報を提供しています
  2. std::threadメインスレッドに結合される前に破棄しています。

最初の問題については、Pete Beckerが示唆std::threadしているように、のコンストラクターにはそれを知る他の方法がないため、関数が呼び出されるオブジェクトを提供する必要があります。threadLoop()構築しているオブジェクトで関数を呼び出したいと仮定すると、次のConnectionように実行できます。

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

内部的には、コンストラクターが呼び出しますthis->threadLoop()(もちろん、それ自体ではなく、受け取っthisConnection*パラメーターはどこにありますか)。std::threadそして、あなたは元気になります。

2番目の問題はstd::thread、メインスレッドに参加せずに、起動直後に破棄されることです。これにより、が呼び出されますterminate()が、これは適切ではありません。もう一度、ピートは良い代替案を提案します。上記のコードを次のように置き換えます。

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

このコードの前の状況は次のとおりです。

  • 些細なstd::threadオブジェクトがありますがconnectionThread、これは実際にはスレッドを表していません

コードの最初の行を実行した後:

  • あなたはまだ持っていますconnectionThread
  • std::threadまた、オブジェクトで表されるライブスレッドがあります。これはコンストラクターthrの最後で破棄され、メインスレッドに結合されないため、への呼び出しが発生します。Connectionterminate()

幸いなことに、コードの2行目が役に立ちます。それを実行した後:

  • 些細な、、がありますがstd::threadthrこれは実際のスレッドを表していないため、安全に破棄できます(したがって、結合できません)。
  • 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のコンストラクターは何らかの形式の関数を期待します。を使用して、フリー関数、静的メンバー関数、または引数と一緒にパックされたこれらの1つを渡すことができますstd::bind。非静的メンバー関数を実行するにはstd::mem_fn、それを呼び出すオブジェクトと一緒に渡すために使用する必要があります。

于 2012-09-27T15:19:42.343 に答える