首页 > 解决方案 > 如何处理:“重复连接...”和“计时器不能从另一个线程停止...”

问题描述

我有一个非常大的文件,其中包含简单的结构化 XML 数据(大约 180,000 条记录)。我需要一个显示进度条并使用另一个线程将数据解析到数据库的对话框。困难之一是我需要写入数据的数据库已被主窗口使用。

什么应用程序:

  1. MainWindow 打开数据库并使用它。
  2. 如果单击“解析并写入”操作,则主窗口:(我们的对话)
void MainWindow::on_act_parse_and_write()
{
    // CLOSE DB
    db->close();
    delete db;
    
    // EXEC DLG
    update_omega_base * dlg = new update_omega_base(this);
    dlg->exec();

    // OPEN NEW CONNECTION
    db = new QSqlDatabase();
    *db = QSqlDatabase::addDatabase("QSQLITE");
    db->setDatabaseName(DB_NAME);
    if (!db->open()) {
        QMessageBox::critical(nullptr, "Помилка", "Не можу підключити базу даних MAINWINDOW", QMessageBox::Ok);
        exit(ERROR_CODE);
    }
}
  1. 我的 dlg 创建了一个 gui:

dlg_parse_and_write

  1. 如果单击左键,则程序会创建一个新线程并编辑进度条:
    parse_and_writeToDB *worker = new parse_and_writeToDB();
    worker->moveToThread(&workThread);

    connect(&workThread, &QThread::finished, &workThread, &QObject::deleteLater);
    connect(this, &update_omega_base::startWork, worker, &parse_and_writeToDB::doWork);
    connect(worker, &parse_and_writeToDB::currentRowChanged, this, &update_omega_base::updateCurrentProgress);
    connect(worker, &parse_and_writeToDB::errorDetected, this, &update_omega_base::handleError);

    workThread.start();
  1. “parse_and_writeToDB”类中的 doWork():
    // CREATE CONNECTION TO DATABASE
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(DB_NAME);
    if (!db.open()) {
        emit errorDetected("Не можу відкрити базу даних");
        exit(ERROR_CODE);
    }

    QSqlQuery qry;

    // clear old Omega table
    if(!qry.exec("DELETE FROM " + DB_TABLE_OMEGA))
    {
        emit errorDetected("Не виходить очистити БД перед записом");
        exit(ERROR_CODE);
    }

    // ------- QXmlStreamParser PARSES EVERYTHING and qry ADDS ROWS -------

    qry.clear();
    db.close();
  1. 工作一段时间后,应用程序崩溃。输出:
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
QObject::~QObject: Timers cannot be stopped from another thread

更新#1 - invodeMethod - 太慢了,无论如何工作都是使用主线程完成的。在写入 DB gui 期间感觉很糟糕。

标签: c++multithreadingsqliteqt

解决方案


您可以从不同的线程调用 metaCall。像这样:

QMetaObject::invokeMethod(obj, "slot",
                            Qt::QueuedConnection);

obj 是 QObject 指针,“slot”是您定义为“public SLOTS”的函数


推荐阅读