25

I'm trying to create a program using threads: the main start with a loop. When a test returns true, I create an object and I want that object to work in an other thread then return and start the test .

QCoreApplication a(argc, argv);
while(true){
    Cmd cmd;
    cmd =db->select(cmd);
    if(cmd.isNull()){ 
        sleep(2);  
        continue ;
    }
    QThread *thread = new QThread( );
    process *class= new process ();
    class->moveToThread(thread);
    thread->start();

    qDebug() << " msg"; // this doesn't run until  class finish it's work 
}
return a.exec();

the problem is when i start the new thread the main thread stops and wait for the new thread's finish .

unfamous
  • 611
  • 1
  • 5
  • 14

2 Answers2

77

The canonical Qt way would look like this:

 QThread* thread = new QThread( );
 Task* task = new Task();

 // move the task object to the thread BEFORE connecting any signal/slots
 task->moveToThread(thread);

 connect(thread, SIGNAL(started()), task, SLOT(doWork()));
 connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));

 // automatically delete thread and task object when work is done:
 connect(task, SIGNAL(workFinished()), task, SLOT(deleteLater()));
 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

 thread->start();

in case you arent familiar with signals/slots, the Task class would look something like this:

class Task : public QObject
{
Q_OBJECT
public:
    Task();
    ~Task();
public slots:
    // doWork must emit workFinished when it is done.
    void doWork();
signals:
    void workFinished();
};
smerlin
  • 6,446
  • 3
  • 35
  • 58
  • thank you it worked . but now i get : get QObject: Cannot create children for a parent that is in a different thread. – unfamous Jun 14 '12 at 19:00
  • You must create those children from the `Task` code that already runs in the target thread, or before the object is moved to the target thread. – Kuba hasn't forgotten Monica Jun 14 '12 at 23:12
  • 3
    smerlin: Kudos for a very nice answer. – Kuba hasn't forgotten Monica Jun 14 '12 at 23:12
  • I wonder what to do if you want to send parameters to doWork()? Could you send parameters directly or would you have to deliver them some other way. Then maybe using events would be better. – NoDataDumpNoContribution Sep 03 '14 at 09:49
  • @Trilarion: Either you pass parameters to the Task constructor and store them as member variables, or use the signal/slot system. – smerlin Sep 05 '14 at 18:03
  • @smerlin: your code has a bug, the 3rd connect should use the task as source object, like in https://wiki.qt.io/QThreads_general_usage. Not doing so can lead to destruction failures. – transistor Sep 12 '17 at 16:27
  • @transistor I do not think this is an issue, since the objects should be deleted in the order of the connect calls (thus the `task` will be deleted before `thread` is deleted). I will update my answer nontheless to match this new offical example. – smerlin Jan 11 '19 at 21:02
1

I don't know how you structured your process class, but this is not really the way that moveToThread works. The moveToThread function tells QT that any slots need to be executed in the new thread rather than in the thread they were signaled from. (edit: Actually, I now remember it defaults to the tread the object was created in)

Also, if you do the work in your process class from the constructor it will not run in the new thread either.

The simplest way to have your process class execute in a new thread is to derive it from QThread and override the run method. Then you never need to call move to thread at all.

jlunavtgrad
  • 997
  • 1
  • 11
  • 21
  • ok thanks for your reply i thought that movetothread do the job . i'm going to use you idea – unfamous Jun 14 '12 at 13:49
  • It will only work that way if you never want any signals nor slots in your worker code. As soon as you do, it's easier to derive from QObject. You will normally want to have multiple worker QObjects per thread. The usual way of spawning a thread per each task to be done is, well, braindead. It adds thread switching overhead where none is needed. – Kuba hasn't forgotten Monica Jun 14 '12 at 17:45
  • You can cheat and derive from QThread and add signals and slots to it, but it becomes really unintuitive. A QThread is an object that controls a thread. When you run QThread's slots within the thread itself, you create a Frankenstein that's both a thread controller and a thread. And, again, it becomes a single-purpose thread. – Kuba hasn't forgotten Monica Jun 14 '12 at 17:47
  • 1
    The only reason to derive from QThread is... well, there's no reason. QThread spins an event loop and you can always move a QObject to it. That way your worker object's lifetime is not the same as the lifetime of the thread. Why not reuse the thread if there's more work to do? And so on... Qt's documentation entirely missed the point of explaining all this :( – Kuba hasn't forgotten Monica Jun 14 '12 at 17:50
  • 2
    @KubaOber: There once was a reason... once upon a time `QThread` was an abstract class, and you had to derive and reimplement `run()` and call `exec()` yourself... but well good thing that `QThread` now offers a implementation of `run()` itself. – smerlin Jun 14 '12 at 18:34
  • @KubaOber:QThead only spins an event loop when you don't override run method. Or, if you do override the run method, you can start the event loop by calling exec. The way you use QThread is one way to do it, but not the only way. – jlunavtgrad Jun 14 '12 at 19:49