4

I have stumbled upon this problem, as others haves: QThread won't stop / does not process a signal QThread - Using a slot quit() to exit the thread

The problem is that I want to have a worker thread started, do some job (which involves sending signals to other threads in my code, and receiving signals asynchronously) and then exit. But I want this thread to be synchronized with the code that is starting it. In other words, I want the execution in the code which creates the worker thread to be halted until the worker thread is done its job.

But it seems this is not possible in Qt. The reason is that the worker's QThread.quit() slot cannot be signaled from within the thread itself. The event loop which listens for signals to this slot, should reside in the same thread that created the worker thread. This means the creating thread should not be blocked, otherwise the worker thread never stops.

Which brings me to my question, that what is the point of QThread.wait() then? I think this function should just be stuck at the end of the program to make sure all the threads have exited, but it cannot actually be used to synchronize threads, at least it cannot be used to synchronize a worker thread, with the thread that created it. Because if the QThread.wait() is called from the creating thread, it blocks its event loop, which will block the worker thread's interface, which will prevent it from ever exiting.

Am I missing something?

I thought I need to add a code snippet:

for (auto i = myVector.begin(); i < myVector.end(); ++i)
{

    // 5-line best practice creation for the thread
    QThread*  workerThread       = new QThread;
    MyWorkerObject* workerObject = new MyWorkerObject(0);
    workerObject->moveToThread(workerThread);
    QObject::connect(workerThread, SIGNAL(started()), workerObject, SLOT(init()));
    QObject::connect(workerThread, SIGNAL(finished()), workerObject, SLOT(deleteLater()));  

    // Stop mechanism
    QObject::connect(workerObject, SIGNAL(finished()), workerThread, SLOT(quit()));

    // Start mechanism
    wokerThread->start();

    // Invoking the work
   QMetaObject::invokeMethod(workerObject, "StartYourJob", Qt::QueuedConnection, Q_ARG(SomeType, *i));

    // Synchronization   
   workerThread->wait();
   delete wokerThread;
}
Community
  • 1
  • 1
Ali B
  • 491
  • 1
  • 5
  • 14
  • 3
    `I want the execution in the code which creates the worker thread to be halted until the worker thread is done its job.` It looks like you don't need a thread at all. – Alex F Nov 19 '13 at 13:56
  • Alex, as I mentioned, the worker's job "involves sending signals to other threads in my code, and receiving signals asynchronously". If I don't create a thread at all, there won't be an event loop to listen for signals... – Ali B Nov 19 '13 at 14:31
  • `QThread::wait` is needed for cleanup. It waits until timeout or thread is finished. You shouldn't delete object of running thread since it can lead to unsuspected errors, so before delete you should call `wait(someInterval)` – Marek R Nov 19 '13 at 14:32
  • That's what I am doing Marek. Please see the code snippet I added... – Ali B Nov 19 '13 at 15:10
  • Move your `workerThread` to ... `workerThread`. In that case your QThread will be able to handle events it's own event loop. – Arman Oganesyan Dec 04 '22 at 23:36

3 Answers3

4

I finally found my answer here: http://comments.gmane.org/gmane.comp.lib.qt.user/6090

In short, if QThread::quit() is invoked as a slot, the event loop handler of the creating thread will deal with it, which is not what I want.

I should call it directly. So when the workerObject finishes its job, instead of sending a signal (which has to pass through the blocked creating thread), it should directly call its container's quit:

this->thread()->quit();

This would be the exit point of the workerObject. Now there is no need for the stop mechanism and these lines can be eliminated from the code.

// Stop mechanism
QObject::connect(workerObject, SIGNAL(finished()), workerThread, SLOT(quit()));

Does anybody see any problem with this approach?

Ali B
  • 491
  • 1
  • 5
  • 14
  • Sorry for the late response but you want that signal so when `MyWorkerObject`run() method is done it emits `finished()` and the thread class cleans itself up. Essentially the only thing you are doing with `this->thread()->quit()` is killing the thread and the run method of your `MyWorkerObject` will be terminated without cleanup. You would be better off having a slot that calls a boolean that tells your `MyWorkerObject` `Run()` method to terminate and then when that terminates `finished()` is called and the `workerThread` is cleaned up also automatically. – David May 16 '14 at 16:46
  • So you would have `workerObject::quit() { m_abort = true; }` method and would be called like: `workerObject->quit(); workerThread->join()` – David May 16 '14 at 16:48
1

The purpose of threads is to allow processes to run concurrently (at the same time!), so if you're just creating a thread to do work and waiting on the current thread, you don't need to be using a new thread.

To answer your question of the purpose of QThread::wait(), the Qt documentation states that it is similar to the POSIX function pthread_join. A quick search on pthread_join reveals this link, which states the rationale is as follows: -

The pthread_join() function is a convenience that has proven useful in multi-threaded applications. It is true that a programmer could simulate this function if it were not provided by passing extra state as part of the argument to the start_routine(). The terminating thread would set a flag to indicate termination and broadcast a condition that is part of that state; a joining thread would wait on that condition variable. While such a technique would allow a thread to wait on more complex conditions (for example, waiting for multiple threads to terminate), waiting on individual thread termination is considered widely useful. Also, including the pthread_join() function in no way precludes a programmer from coding such complex waits. Thus, while not a primitive, including pthread_join() in this volume of POSIX.1-2008 was considered valuable.

The pthread_join() function provides a simple mechanism allowing an application to wait for a thread to terminate. After the thread terminates, the application may then choose to clean up resources that were used by the thread. For instance, after pthread_join() returns, any application-provided stack storage could be reclaimed.

The pthread_join() or pthread_detach() function should eventually be called for every thread that is created with the detachstate attribute set to PTHREAD_CREATE_JOINABLE so that storage associated with the thread may be reclaimed.

The interaction between pthread_join() and cancellation is well-defined for the following reasons:

The pthread_join() function, like all other non-async-cancel-safe functions, can only be called with deferred cancelability type.

Cancellation cannot occur in the disabled cancelability state.

Thus, only the default cancelability state need be considered. As specified, either the pthread_join() call is canceled, or it succeeds, but not both. The difference is obvious to the application, since either a cancellation handler is run or pthread_join() returns. There are no race conditions since pthread_join() was called in the deferred cancelability state.

If an implementation detects that the value specified by the thread argument to pthread_join() does not refer to a joinable thread, it is recommended that the function should fail and report an [EINVAL] error.

If an implementation detects that the value specified by the thread argument to pthread_join() refers to the calling thread, it is recommended that the function should fail and report an [EDEADLK] error.

If an implementation detects use of a thread ID after the end of its lifetime, it is recommended that the function should fail and report an [ESRCH] error.

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Merlin, how would you do it then? The worker thread contains a workerobject (workerobject->movetothread(workerthread)) whose job is to send a few signals around to different threads in the code, and wait for their responses through its slots. If the workerobject is not contained within the worker thread, how else could it receive signals from the other threads? It needs an event loop. Maybe what I need is really a QEventLoop, but I thought it would be appropriate to do this through a worker thread. – Ali B Nov 19 '13 at 14:44
  • @AliB, It's quite difficult to advise, without seeing your current code, but it sounds like the worker thread should be your main thread, assuming you've created it as an object on a different thread. The main thread automatically has an event loop when you call QApplication::exec(). If the workerobject doesn't do very much, but coordinate the other threads, then it should be fine on the main thread. – TheDarkKnight Nov 19 '13 at 14:59
  • Thanks Merlin, added the code. I have a loop running and I want to create the thread to do the job for each item. I can absolutely do this in a different but inconvenient way. But I want to understand how to do this conveniently without having to break my loop into member variables of the creating thread, and having signals to increment it, etc... – Ali B Nov 19 '13 at 15:04
  • The wait and delete of the workerThread is redundant. You connect the signal finished() to the workerThread's deleteLater, which will delete the thread when it has finished. Assuming the for loop is on the main thread, you don't need to call wait, just let it tick along processing any events that it may receive. If you want a thread to finish, call its quit function. – TheDarkKnight Nov 19 '13 at 15:08
  • Also, rather than invoking the function you want to start on your workerObject, connect the thread's started signal to a slot in the workerObject. – TheDarkKnight Nov 19 '13 at 15:10
  • It may be a good idea for you to read this: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ – TheDarkKnight Nov 19 '13 at 15:11
0

QThread::wait() is not what you need. This function is exactly what you mentioned, it waits for thread termination.

bool QThread::wait ( unsigned long time = ULONG_MAX )

Blocks the thread until either of these conditions is met:

The thread associated with this QThread object has finished execution (i.e. when it returns from run()). This function will return true if the thread has finished. It also returns true if the thread has not been started yet.

time milliseconds has elapsed. If time is ULONG_MAX (the default), then the wait will never timeout (the thread must return from run()). This function will return false if the wait timed out.

If you need to synchronize two threads (Your main thread and created thread) then I recommend using signals and slots to signal which one is ready (trigger a isReady bool) and have a while (!isReady) { sleep(1ms); processEvents(); } loop going. May not be the best way but should work.

David
  • 692
  • 8
  • 21
  • Also true about what others are saying; If you are only running one set of code at one time, then you don't need a thread. – David Nov 19 '13 at 14:27