What is the use of QThread.wait() function?

17,106

Solution 1

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?

Solution 2

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.

Share:
17,106
Ali B
Author by

Ali B

Updated on June 25, 2022

Comments

  • Ali B
    Ali B almost 2 years

    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;
    }