Qt5.2.0; Debian Wheezy: деструктор QSqlDatabase вызывает segfault

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

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

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

2

Решение

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

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

Также вы можете попробовать это disconnect db переменная, так что некоторая ожидающая транзакция не пытается что-то сделать с db после того, как его нет.

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

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

Надеюсь, это поможет.

1

Другие решения

похоже, у вас нет правильного способа создания и уничтожения базы данных QD

создать способ должен понравиться

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

По вопросам рекламы [email protected]