У меня есть приложение, которое использует класс-оболочку для доступа к базе данных 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 и сбою приложение?
В 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