Results 1 to 7 of 7

Thread: QThread question

  1. #1
    Join Date
    Oct 2011
    Location
    Germany
    Posts
    27
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Thanked 2 Times in 2 Posts

    Default QThread question

    Hi,

    I'm experimenting with threads.
    My goal is to write a program, which exports data from a DB to XML.
    I'm planing to create 2 or 3 worker threads, that does the job.
    When a thread is finished with a DB table, a new table must be assigned to the thread.
    So I have to know which thread object is finished.

    I wrote the following thread class for testing:

    Qt Code:
    1. #ifndef KCOUNTERTHREAD_H
    2. #define KCOUNTERTHREAD_H
    3.  
    4. #include <QThread>
    5.  
    6. class KCounterThread : public QThread
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit KCounterThread(int id, QObject *parent = 0, int maxValue = 100, int waitTime = 100);
    11.  
    12. void run();
    13.  
    14. int maxValue() const;
    15. void setMaxValue(int value);
    16. int waitTime() const;
    17. void setWaitTime(int value);
    18. int id() const;
    19.  
    20. signals:
    21. void counterChanged(int value);
    22. void threadFinished(KCounterThread*);
    23.  
    24. private:
    25. int m_maxValue;
    26. int m_waitTime;
    27. int m_id;
    28. };
    29.  
    30. #endif // KCOUNTERTHREAD_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "kcounterthread.h"
    2.  
    3. KCounterThread::KCounterThread(int id, QObject *parent, int maxValue, int waitTime)
    4. : QThread(parent), m_id(id), m_maxValue(maxValue), m_waitTime(waitTime)
    5. {
    6. }
    7.  
    8. void KCounterThread::run()
    9. {
    10. for (int n = 0; n < m_maxValue; n++)
    11. {
    12. emit counterChanged(n);
    13. msleep(m_waitTime);
    14. }
    15. emit threadFinished(this);
    16. }
    17.  
    18. int KCounterThread::maxValue() const
    19. {
    20. return m_maxValue;
    21. }
    22.  
    23. void KCounterThread::setMaxValue(int value)
    24. {
    25. if (!isRunning())
    26. m_maxValue = value;
    27. }
    28.  
    29. int KCounterThread::waitTime() const
    30. {
    31. return m_waitTime;
    32. }
    33.  
    34. void KCounterThread::setWaitTime(int value)
    35. {
    36. if (!isRunning())
    37. m_waitTime = value;
    38. }
    39.  
    40. int KCounterThread::id() const
    41. {
    42. return m_id;
    43. }
    To copy to clipboard, switch view to plain text mode 

    As you can see I emit a self declared signal threadFinished(this) at the end of the run() method.
    My test program looks like this:
    Qt Code:
    1. void MainWindow::on_pushButton2_clicked()
    2. {
    3. counterThread1 = new KCounterThread(1, this, 500, 10);
    4. counterThread2 = new KCounterThread(2, this, 500, 5);
    5.  
    6. ui->progressBar1->setMaximum(counterThread1->maxValue() - 1);
    7. ui->progressBar2->setMaximum(counterThread2->maxValue() - 1);
    8. ui->progressBar1->setValue(0);
    9. ui->progressBar2->setValue(0);
    10. connect(counterThread1, SIGNAL(counterChanged(int)), this, SLOT(counter1Changed(int)));
    11. connect(counterThread2, SIGNAL(counterChanged(int)), this, SLOT(counter2Changed(int)));
    12. connect(counterThread1, SIGNAL(finished()), this, SLOT(counter1Finished()));
    13. connect(counterThread2, SIGNAL(finished()), this, SLOT(counter2Finished()));
    14. connect(counterThread1, SIGNAL(threadFinished(KCounterThread*)), this, SLOT(counterFinished(KCounterThread*)));
    15. connect(counterThread2, SIGNAL(threadFinished(KCounterThread*)), this, SLOT(counterFinished(KCounterThread*)));
    16. counterThread1->start();
    17. counterThread2->start();
    18. }
    19. void MainWindow::counter1Changed(int value)
    20. {
    21. ui->progressBar1->setValue(value);
    22. }
    23.  
    24. void MainWindow::counter2Changed(int value)
    25. {
    26. ui->progressBar2->setValue(value);
    27. }
    28.  
    29. void MainWindow::counter1Finished()
    30. {
    31. ui->plainTextEdit->appendPlainText("Thread 1 finished!!!");
    32. }
    33.  
    34. void MainWindow::counter2Finished()
    35. {
    36. ui->plainTextEdit->appendPlainText("Thread 2 finished!!!");
    37. }
    38.  
    39. void MainWindow::counterFinished(KCounterThread *counterThread)
    40. {
    41. ui->plainTextEdit->appendPlainText(QString("Thread %1 finished. (This is my signal)").arg(counterThread->id()));
    42. }
    To copy to clipboard, switch view to plain text mode 
    I get this output:
    Qt Code:
    1. Thread 2 finished. (This is my signal)
    2. Thread 2 finished!!!
    3. Thread 1 finished. (This is my signal)
    4. Thread 1 finished!!!
    To copy to clipboard, switch view to plain text mode 

    My question is:
    Is this the right way to do this or is there a better way?

    Thanks in advance
    Insanity: doing the same thing over and over again and expecting different results.
    Albert Einstein

  2. #2
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,540
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanked 284 Times in 279 Posts

    Default Re: QThread question

    No because with this run() method You don't have an event loop in thread. It should be something like this :
    Qt Code:
    1. #ifndef KCOUNTERTHREAD_H
    2. #define KCOUNTERTHREAD_H
    3.  
    4. #include <QThread>
    5.  
    6. class KCounterThread : public QThread
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit KCounterThread(int id, QObject *parent = 0, int maxValue = 100, int waitTime = 100);
    11.  
    12. void run();
    13.  
    14. int maxValue() const;
    15. void setMaxValue(int value);
    16. int waitTime() const;
    17. void setWaitTime(int value);
    18. int id() const;
    19.  
    20. signals:
    21. void counterChanged(int value);
    22. void threadFinished(KCounterThread*);
    23. void oneStep();//new slot definition
    24. private:
    25. int m_maxValue;
    26. int m_waitTime;
    27. int m_id;
    28. int m_stepNumber;//new variable definition
    29. };
    30.  
    31. #endif // KCOUNTERTHREAD_H
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. void KCounterThread::run()
    2. {
    3. m_stepNumber = 0;
    4. QTimer::singleShot(0, this, SLOT(oneStep()));
    5. QThread::run();
    6. }
    7.  
    8. void KCounterThread::oneStep()
    9. {
    10. if( m_stepNumber++ < m_maxValue )
    11. {
    12. emit counterChanged(n);
    13. QTimer::singleShot(m_waitTime, this, SLOT(oneStep()));
    14. }
    15. else
    16. emit threadFinished(this);
    17. }
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts

    Default Re: QThread question

    Quote Originally Posted by Lesiok View Post
    No because with this run() method You don't have an event loop in thread.
    Why would the thread need an event loop?

    Quote Originally Posted by Lesiok View Post
    Qt Code:
    1. void KCounterThread::run()
    2. {
    3. m_stepNumber = 0;
    4. QTimer::singleShot(0, this, SLOT(oneStep()));
    5. QThread::run();
    6. }
    To copy to clipboard, switch view to plain text mode 
    Why would one want the thread to fire timer signals but do the process in the main thread? Usually the worker thread is the one that should to the work.

    Quote Originally Posted by ObiWanKenobe View Post
    My goal is to write a program, which exports data from a DB to XML.
    I'm planing to create 2 or 3 worker threads, that does the job.
    When a thread is finished with a DB table, a new table must be assigned to the thread.
    So I have to know which thread object is finished.
    Sounds like you want to have a look at thread pools. i.e. QThreadPool

    Cheers,
    _

  4. #4
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android
    Thanked 342 Times in 324 Posts

    Default Re: QThread question

    Isn't it simpler to separate the "thread" and "worker" logic ?
    Qt Code:
    1. #include <QThread>
    2. #include <QApplication>
    3. #include <QDebug>
    4. #include <QTimer>
    5.  
    6. class Worker : public QObject{
    7. Q_OBJECT
    8. public:
    9. Worker(int njobs) : m_njobs(njobs){
    10. }
    11. public slots:
    12. void doJob(){
    13. qDebug() << "Working... " << m_njobs << QThread::currentThread();
    14. --m_njobs;
    15. if (m_njobs <= 0){
    16. emit done();
    17. } else{
    18. QTimer::singleShot(0,this,SLOT(doJob()));
    19. }
    20. }
    21. signals:
    22. void done();
    23. private:
    24. int m_njobs;
    25. };
    26.  
    27. int main(int argc, char ** argv){
    28. QApplication app(argc,argv);
    29. qDebug() << "GUI Thread " << QThread::currentThread();
    30. Worker * worker = new Worker(5);
    31. QThread * thread = new QThread();
    32. worker->moveToThread(thread);
    33. QObject::connect(thread, SIGNAL(started()), worker, SLOT(doJob()));
    34. QObject::connect(worker, SIGNAL(done()), thread, SLOT(quit()));
    35. QObject::connect(thread, SIGNAL(finished()), &app, SLOT(quit()));
    36. thread->start();
    37. int r = app.exec();
    38. delete worker;
    39. delete thread;
    40. return r;
    41. }
    42.  
    43. #include "moc_main.cpp"
    To copy to clipboard, switch view to plain text mode 

    // program output:
    [New Thread 3892.0x2bc]
    warning: GUI Thread QThread(0x187658a8)

    [New Thread 3892.0x1a28]
    warning: Working... 5 QThread(0x1876a338)

    warning: Working... 4 QThread(0x1876a338)

    warning: Working... 3 QThread(0x1876a338)

    warning: Working... 2 QThread(0x1876a338)

    warning: Working... 1 QThread(0x1876a338)


    Program exited normally.

  5. #5
    Join Date
    Oct 2011
    Location
    Germany
    Posts
    27
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Thanked 2 Times in 2 Posts

    Default Re: QThread question

    Thank you all for your replies.

    @stampede:
    Your solution keeps the GUI responsive, but I want to parallelize the table exports.
    I have about 30 tables and I want to export 2-3 of them at the same time.
    Everytime a thread finises the export a new table will be assigned to it from the list of tables (QStringList).

    @anda_skoa:
    QThreadPool could be an alternative. I have to study it in more detail.
    Insanity: doing the same thing over and over again and expecting different results.
    Albert Einstein

  6. #6
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android
    Thanked 342 Times in 324 Posts

    Default Re: QThread question

    ... but I want to parallelize the table exports
    I can't see any problems with this if you disconnect the threading logic and worker logic. Now you have a single object, which is a "worker-in-thread", I just want to point out that its more reusable to have a "worker" and "thread" separately. Imagine a Worker from my example being a single db table exporter. This way you can run all of them in GUI thread, assign separate thread to each Worker, or even push 2-3 Workers to the same thread. In order to reuse Workers, you can catch the "done" signal from the Worker and assign it next table (or set of tables).
    This way you have everything nicely structured - if you decide to change the threading model later, you won't need to change the db table export code, because a Worker doesn't care if it works in main or any other thread.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,373
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QThread question

    For me QtConcurrent seems the easiest approach to take.

    Qt Code:
    1. QStringList tables = QStringList() << "tableA" << "tableB" << "tableC" << ...;
    2. QFuture<void> future = QtConcurrent::map(tables, myFuncThatExportsATable);
    3. // ...
    To copy to clipboard, switch view to plain text mode 

    One can use QFutureWatcher to be notified about progress of operations using signals.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. QThread, moveToThread question
    By Anenja in forum Qt Programming
    Replies: 16
    Last Post: 6th March 2013, 12:01
  2. QThread Question
    By ionutdanila in forum Newbie
    Replies: 7
    Last Post: 6th January 2011, 08:23
  3. QTimer / QThread question
    By Galen in forum Newbie
    Replies: 13
    Last Post: 20th April 2010, 22:39
  4. basic qthread question
    By zl2k in forum Qt Programming
    Replies: 2
    Last Post: 9th September 2008, 22:43
  5. QThread exit()/quit() question
    By TheKedge in forum Qt Programming
    Replies: 1
    Last Post: 28th August 2006, 15:38

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.