2014-01-26 3 views
2

У меня есть приложение, которое использует класс-оболочку для доступа к базе данных MySQL. Поскольку доступ к базе данных осуществляется в разных местах приложения, а приложение многопоточно, класс-оболочка используется для минимизации количества повторяющегося кода, необходимого для доступа к БД.Qt5.2.0; Debian Wheezy: деструктор QSqlDatabase вызывает segfault

Я где-то читал, что QSqlDatabase должен быть сконструирован, использован, а затем разрушен внутри той же нити. Недокументированное/неподдерживаемое поведение может возникать, если вы создаете соединение в одном потоке, а затем уничтожаете его в другом. Чтобы предотвратить это, оболочка создает соединение непосредственно перед настройкой QSqlQuery, а затем закрывает и удаляет это соединение, когда запрос выполняется. Настройка пула соединений и поддержание их активности во время выполнения приложения не является осуществимой, поскольку в любой момент времени существует любое количество потоков, каждый из которых может потребоваться выполнить несколько задач БД асинхронно, поэтому не существует 1-1 между потоками и подключениями к базам данных.

Проблема в том, что после того, как приложение запустилось некоторое время, оно сработает с segfault, который обвиняет деструктор QSqlDatabase. Нехорошо, что ошибка появляется только после того, как приложение работает некоторое время и выполнило многочисленные запросы. (Иногда он падает через 15 минут, иногда через несколько часов). Самые последние трассировки стека:

Program received signal SIGSEGV, Segmentation fault. 
[email protected]@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 [email protected]@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; 
} 

Почему это довольно простой деструктор вызвать Segfault и сбою приложение?

ответ

1

Вы пытались использовать deleteLater() вместо того, чтобы звонить delete db;.

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

Кроме того, вы можете попробовать это disconnectdb переменной, так что некоторые незавершенные транзакции не пытается сделать что-то к db после его нет.

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

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

Надежда, что помогает.

+0

В Qt 5.2.0, его не выглядит так, как 'QSqlDatabase' наследует' QObject'. Таким образом, я не могу вызвать deleteLater() или disconnect(). Когда я пытаюсь скомпилировать, он дает следующее: 'db.cpp: В деструкторе 'DB :: ~ DB()': db.cpp: 28: 13: ошибка: 'class QSqlDatabase' не имеет члена с именем 'disconnect ' ДБ.cpp: 29: 13: ошибка: «класс QSqlDatabase» не имеет имени с именем «deleteLater» – user3233311

-1

кажется, что вы не имеете правильный способ создать и уничтожить QDatabase

создать путь хотел

QUuid uniqueId = QUuid::createUuid(); 
db = new QSqlDatabase(); 
*db = QSqlDatabase::addDatabase("QMYSQL", uniqueId.toString()); 
db->setHostName(...); 
db->setDatabaseName(...); 
db->setUserName(...); 
db->setPassword(...); 

и уничтожить как

db->close(); 
delete db; 
QSqlDatabase::removeDatabase(db->connectionName()); 
+1

Удаленный объект, удаленный от UB – Basilevs

+0

Да, я просто копирую свой код и объединяю код пользователя3233311. должен использовать QString, чтобы сначала получить connectionName. Спасибо за ваш комментарий. – 0xFFFFFFFF

Смежные вопросы