3

私が取り組んでいる XMLRPC サーバー (xmlrpc-c に基づく) では、次の関数を使用して、スレッドが MySQL 接続を確立してデータを取得する必要がある場合があります。

Distribution getEntitySetFromMysql( int id ) {

    Distribution result;

    try {
        sql::Driver *driver = get_driver_instance();
        sql::Connection *con = driver->connect( (std::string)DBHOST, (std::string)USER, (std::string)PASSWORD);
        con->setSchema( (std::string)DATABASE );

        sql::Statement *stmt = con->createStatement();
        std::stringstream query;
        query << "SELECT concept_id, weight FROM entity_set_lines WHERE entity_set_id = " << id;
        sql::ResultSet *res = stmt->executeQuery ( query.str() );

        while (res->next()) {
            result[ res->getInt("concept_id") ] = res->getDouble("weight");
        }

        delete res;
        delete stmt;
        con->close();
        delete con;

    } catch (sql::SQLException &e) {
        std::cout << "ERROR: SQLException in " << __FILE__;
        std::cout << " (" << __func__<< ") on line " << __LINE__ << std::endl;
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047) {
            std::cout << "\nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
        }

    } catch (std::runtime_error &e) {

        std::cout << "ERROR: runtime_error in " << __FILE__;
        std::cout << " (" << __func__ << ") on line " << __LINE__ << std::endl;
        std::cout << "ERROR: " << e.what() << std::endl;

    }

    return result;
}

すべて正常に動作しますが、スレッドがこのコードを実行して結果を正常に返した後、スレッドはハングしたままになり、終了しません。このアプローチの何が問題なのですか? これはどれほど根本的に間違っているのでしょうか? MySQL コネクタはスレッドセーフですか?

4

3 に答える 3

4

sql::Driver::threadInit()解決策を探し回っているときに、との言及に出くわしましたsql::Driver::threadEnd()。ただし、私は C++ コネクタのバージョン 1.0.5 を使用していたため、これらの機能は利用できませんでした。driver->threadInit();ドライバーインスタンスを取得した後、関数の最後に を追加するとdriver->threadEnd();、この問題は解決されました。

以下は、 MySQL の 1.1.0 変更履歴でのこのスレッドの開始および終了機能に関する言及です。

Driver::threadInit() および Driver::threadEnd() メソッドを追加しました。スレッド化されたクライアントのすべてのスレッドは、Connector/C++ で他の処理を行う前に、スレッドの開始時に Driver::threadInit() を呼び出す必要があり、すべてのスレッドは終了時に Driver::threadEnd() を呼び出す必要があります。examples/pthreads.cpp で使用方法を示す例を見つけることができます。スレッド間で接続を共有することは強くお勧めしません。特定の (文書化されていない) ミューテックスを設定すれば、理論的には可能ですが、まったくサポートされていません。スレッドごとに 1 つの接続を使用します。同時に同じ接続を使用する 2 つのスレッドを作成しないでください。MySQL マニュアルのスレッドに関する C API ノートを確認してください。Connector/C++ は C API をラップします。(ローリン、アンドレイ、ウルフ)

TL;DR: この問題に遭遇した場合は、C++ MySQL コネクタのバージョンが >= 1.1.0 であることを確認し、sql::Driver::threadInit()およびsql::Driver::threadEnd()メソッドを使用して接続コードを囲んでください。

于 2013-04-23T13:05:39.810 に答える