2

ラッパー クラスを使用して MySQL データベースにアクセスするアプリがあります。データベースはアプリ内のさまざまな場所でアクセスされ、アプリはマルチスレッドであるため、ラッパー クラスを使用して、DB へのアクセスに必要な反復コードの量を最小限に抑えます。

QSqlDatabase同じスレッド内で a を構築、使用、および破棄する必要があることをどこかで読みました。あるスレッドで接続を作成し、別のスレッドで破棄すると、文書化されていない/サポートされていない動作が発生する可能性があります。これを防ぐために、ラッパーは を設定する直前に接続を作成しQSqlQuery、クエリが完了するとその接続を閉じて削除します。接続のプールを設定し、アプリの実行中にそれらを維持することは、実際には実行可能ではありません。これは、任意の時点で実行されているスレッドの数が多く、それぞれが複数の DB タスクを非同期で実行する必要がある場合があるためです。まず、スレッドとデータベース接続の間の 1 対 1 の相関関係。

問題は、アプリがしばらく実行された後、デストラクタを非難する segfault でクラッシュすることQSqlDatabaseです。奇妙なことは、アプリがしばらく実行され、多数のクエリが実行された後にのみエラーが表示されることです。(15 分後にクラッシュすることもあれば、数時間後にクラッシュすることもあります)。最新のスタック トレース:

Program received signal SIGSEGV, Segmentation fault.
pthread_cond_timedwait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:174
174     ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: No such file or     directory.
(gdb) where
#0  pthread_cond_timedwait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:174
#1  0x00007ffff32f55b4 in my_thread_global_end ()
   from /opt/Qt/5.2.0/gcc_64/plugins/sqldrivers/libqsqlmysql.so
#2  0x00007ffff32f40a5 in my_end ()
   from /opt/Qt/5.2.0/gcc_64/plugins/sqldrivers/libqsqlmysql.so
#3  0x00007ffff32db5c7 in mysql_server_end ()
   from /opt/Qt/5.2.0/gcc_64/plugins/sqldrivers/libqsqlmysql.so
#4  0x00007ffff32cd806 in ?? ()
   from /opt/Qt/5.2.0/gcc_64/plugins/sqldrivers/libqsqlmysql.so
#5  0x00007ffff32cd829 in ?? ()
   from /opt/Qt/5.2.0/gcc_64/plugins/sqldrivers/libqsqlmysql.so
#6  0x00007ffff7657537 in ?? () from /opt/Qt/5.2.0/gcc_64/lib/libQt5Sql.so.5
#7  0x00007ffff7657e7d in QSqlDatabase::~QSqlDatabase() ()
   from /opt/Qt/5.2.0/gcc_64/lib/libQt5Sql.so.5
#8  0x00007ffff7659204 in ?? () from /opt/Qt/5.2.0/gcc_64/lib/libQt5Sql.so.5
#9  0x00000000004143c2 in DB::~DB (this=0x7ffff0829200,
    __in_chrg=<optimized out>) at db.cpp:32
#10 0x000000000042e758 in WeatherOutcome::MassInsert (
    this=0x7ffff0829550, inputVector=...) at weatheroutcome.cpp:96

ラッパー クラスのヘッダー ファイルは次のとおりです。

#ifndef DB_H
#define DB_H
#include <QString>
#include <QtSql> 
#include <QSqlQuery>
#include <QSqlError>
#include <QUuid>
class DB
{
public:
    DB();
    ~DB();
    bool SetQuery(QString query);
    bool Exec();
    void manualConnect();
protected:
    QSqlQuery query;
    QSqlDatabase* db;
};

#endif // DB_H

ラッパー クラス CPP ファイル:

#include db.h
DB::DB()
{

}
DB::~DB()
{
    if (query.isActive())
    {
        query.finish();
        query.clear();
    }
    if (db != NULL)
    {
        QString connName = db->connectionName();
        db->close();
        delete db;
        db = NULL;
        try
        {
            QSqlDatabase::removeDatabase(connName);
        }


        catch(...)
        {

        }
    }
}

void DB::manualConnect()
{
    QUuid uniqueId = QUuid::createUuid();
    QString connectionID = uniqueId.toString();
    QSqlDatabase::addDatabase("QMYSQL", connectionID);

    db = new QSqlDatabase(QSqlDatabase::database(connectionID, false));
    db->setHostName("127.0.0.1");
    db->setDatabaseName("my_db_name");
    db->setUserName("username");
    db->setPassword("password");

    db->open();
}

bool DB::Exec()
{
    return query.exec()  ;
}

bool DB::SetQuery(QString queryString)
{
    manualConnect();
    if (db)
    {
        if (db->isOpen())
        {
            query = QSqlQuery(*db);
            return query.prepare(queryString);
        }
        return false;
    }
    else
        return false;
}

このかなり単純なデストラクタがセグメンテーション違反を引き起こし、アプリをクラッシュさせるのはなぜでしょうか?

4

2 に答える 2

1

deleteLater()を呼び出す代わりに使用してみましたかdelete db;

http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#deleteLater

また、いくつかの保留中のトランザクションが、変数がなくなった後に何かをしようとしないようにdisconnect、変数を試してみることもできます。dbdb

http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#disconnect

http://qt-project.org/doc/qt-5.0/qtcore/objecttrees.html

それが役立つことを願っています。

于 2014-01-27T00:14:01.590 に答える