Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
222 views
in Technique[技术] by (71.8m points)

c++ - How to deal: "Duplicate connection..." and "Timers cannot be stopped from another thread..."

I have a very large file with simple structured XML data (about 180,000 records). I need a dialog that will show a progress bar and parse the data to the database using another thread. One of the difficulties is that the database to which I need to write data is already in use by the main window.

What app does:

  1. MainWindow opens database and works with it.
  2. If action "Parse and write" is clicked then mainwindow: (our dialogue)
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. My dlg creates a gui:

dlg_parse_and_write

  1. If left button clicked then program creates a new thread and edits progressBar:
    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. doWork() in "parse_and_writeToDB" class:
    // 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. After working for a while, the application crashes. Output:
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
QObject::~QObject: Timers cannot be stopped from another thread

UPDATE #1 - invodeMethod - is too slow and the work anyway is done using main thread. During writing to DB gui feels bad.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can call metaCall from different thread. Like this:

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

obj is the QObject pointer, "slot" is the function you define as "public SLOTS"


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...