Qt Slot Function Thread

 
Qt Slot Function Thread 4,8/5 8131 votes

QtUtils provides convenience functions for accessing Qt objects in a thread safe way.Qt requires that all GUI objects exist in the MainThread and that access to these objects is only made from the MainThread (see Qt documentation).This, while understandable, imposes significant limits on Python applications where threading is easy.While there are solutions using Qt signals, slots and a QThread, these require significant boiler plate code that we believe is unnecessary.

Note

There is some debate as to whether using Python threads with any part of the Qt library is safe, however this has been recently challenged. The QtUtils library only instantiates a QEvent and calls QCoreApplication.postEvent() from a Python thread. It seems likely that as long as the underlying Python threading implementation matches the underlying Qt threading implementation for your particular platform, that there is no issue with how we have written this library. While we have not observed any issues with our library (and we have used it extensively on Windows, OSX and Ubuntu), this does not mean all platforms will behave in the same way. If this matters to you, we suggest you confirm the underlying thread implementation for your build of Python and Qt.

Examples¶

We utilise the Qt event loop to execute arbitrary methods in the MainThread by posting a Qt event to the MainThread from a secondary thread.QtUtils provides a function called inmain which takes a reference to a method to execute in the MainThread, followed by any arguments to be passed to the method.

If this way of function calls across threads are okay, then my problem with function return value and parameters are also solved! I have read somewhere that we should use signal-slots approach when working with threads because it is thread safe in nature! A function is thread-safe if it's safe to invoke it from more than one thread at the same time even if the invocations reference shared data. Events and the event loop Being an event-driven toolkit, events and event delivery play a central role in Qt architecture. This wrapper provides the signals, slots and methods to easily use the thread object within a Qt project. To use it, prepare a QObject subclass with all your desired functionality in it. Then create a new QThread instance, push the QObject onto it using moveToThread(QThread.) of the QObject instance and call start on the QThread instance.

A call to inmain blocks the calling thread until the Qt event loop can process our message, execute the specified method and return the result.For situations where you don’t wait to wait for the result, or you wish to do some other processing while waiting for the result, QtUtils provides the inmain_later function.This works in the same way as inmain, but returns a reference to a Python Queue object immediately.The result can be retrieved from this queue at any time, as shown in the following example:

A short history. Long long ago, subclass QThread and reimplement its run function is the only recommended way of using QThread. This is rather intuitive and easy to used. But when SLOTS and Qt event loop are used in the worker thread, some users do it wro. The code inside the Worker's slot would then execute in a separate thread. However, you are free to connect the Worker's slots to any signal, from any object, in any thread. It is safe to connect signals and slots across different threads, thanks to a mechanism called queued connections.

This of course works directly with Qt methods as well as user defined functions/methods.For example:

As you can see, the change between a direct call to a Qt method, and doing it in a thread safe way, is very simple:

We also provide decorators so that you can ensure the decorated method always runs in the MainThread regardless of the calling thread.This is particularly useful when combined with Python properties.

QtUtils also provides a convenience function for launching a Python thread in daemon mode.inthread(target_method,arg1,arg2,...kwarg1=False,kwargs2=7,...)

Exception handling¶

Typically, exceptions are raised in the calling thread.However, inmain_later and the associated decorator will also raise the exception in the MainThread as there is no guarantee that the results will ever be read from the calling thread.

Using QtUtils from the MainThread¶

When using inmain, or the associated decorator, QtUtils will bypass the Qt Event loop as just immediately execute the specified method.This avoids the obvious deadlock where the calling code is being executed by the Qt event loop, and is now waiting for the Qt event loop to execute the next event (which won’t ever happen because it is blocked waiting for the next event by the calling code).inmain_later still posts an event to the Qt event loop when used from the MainThread.This is useful if you want to execute something asynchronously from the MainThread (for example, asynchronously update the text of a label) but we recommend you do not attempt to read the result of such a call as you risk creating a deadlock.

What if I want to wait for user input in a thread?¶

If you want your thread to wait for user input, then this is not the library for you!We suggest you check out how to Wait in thread for user input from GUI for a Qt solution and/or Python threading events for a Python solution.

API reference¶

class qtutils.invoke_in_main.CallEvent(queue, exceptions_in_main, fn, *args, **kwargs)[source]

An event containing a request for a function call.

class qtutils.invoke_in_main.Caller[source]

An event handler which calls the function held within a CallEvent.

event(self, QEvent) → bool[source]
Qt Slot Function Thread
qtutils.invoke_in_main.get_inmain_result(queue)[source]

Processes the result of qtutils.invoke_in_main.inmain_later().

This function takes the queue returned by inmain_later and blocksuntil a result is obtained. If an exception occurred when executing thefunction in the MainThread, it is raised again here (it is also raised in theMainThread). If no exception was raised, the result from the execution of thefunction is returned.

Parameters

queue – The Python Queue object returned by inmain_later

Returns

The result from executing the function specified in the call toinmain_later

qtutils.invoke_in_main.inmain(fn, *args, **kwargs)[source]
Thread

Execute a function in the main thread. Wait for it to completeand return its return value.

This function queues up a custom QEvent to the Qt event loop.This event executes the specified function fn in the PythonMainThread with the specified arguments and keyword arguments, and returns the result to the calling thread.

This function can be used from the MainThread, but such use will just directly call the function, bypassing the Qt event loop.

Parameters
  • fn – A reference to the function or method to run in the MainThread.

  • *args – Any arguments to pass to fn when it is called from theMainThread.

  • **kwargs – Any keyword arguments to pass to fn when it is calledfrom the MainThread

Returns

The result of executing fn(*args,**kwargs)

qtutils.invoke_in_main.inmain_decorator(wait_for_return=True, exceptions_in_main=True)[source]

A decorator which enforces the execution of the decorated thread to occur in the MainThread.

This decorator wraps the decorated function or method in eitherqtutils.invoke_in_main.inmain() orqtutils.invoke_in_main.inmain_later().

Keyword Arguments
  • wait_for_return – Specifies whether to use inmain (ifTrue) or inmain_later (ifFalse).

  • exceptions_in_main – Specifies whether the exceptions should be raisedin the main thread or not. This is ignored ifwait_for_return=True. If this isFalse, then exceptions may be silenced ifyou do not explicitly useqtutils.invoke_in_main.get_inmain_result().

Returns

The decorator returns a function that has wrapped the decorated functionin the appropriate call to inmain or inmain_later (ifyou are unfamiliar with how decorators work, please see the Pythondocumentation).

Qt Thread Signal Slot

When calling the decorated function, the result is either the result ofthe function executed in the MainThread (if wait_for_return=True)or a Python Queue to be used withqtutils.invoke_in_main.get_inmain_result() at a later time.

qtutils.invoke_in_main.inmain_later(fn, *args, **kwargs)[source]

Queue up the executing of a function in the main thread and return immediately.

This function queues up a custom QEvent to the Qt event loop.This event executes the specified function fn in the PythonMainThread with the specified arguments and keyword arguments, and returnsa Python Queue which will eventually hold the result from the executing offn. To access the result, use qtutils.invoke_in_main.get_inmain_result().

This function can be used from the MainThread, but such use will just directly call the function, bypassing the Qt event loop.

Parameters
  • fn – A reference to the function or method to run in the MainThread.

  • *args – Any arguments to pass to fn when it is called from theMainThread.

  • **kwargs – Any keyword arguments to pass to fn when it is calledfrom the MainThread

Returns

A Python Queue which will eventually hold the result(fn(*args,**kwargs),exception) whereexception=[type,value,traceback].

qtutils.invoke_in_main.inthread(f, *args, **kwargs)[source]

A convenience function for starting a Python thread.

This function launches a Python thread in Daemon mode, and returns areference to the running thread object.

Parameters
  • f – A reference to the target function to be executed in the Python thread.

  • *args – Any arguments to pass to f when it is executed in thenew thread.

  • **kwargs – Any keyword arguments to pass to f when it is executedin the new thread.

Returns

A reference to the (already running) Python thread object

While the purpose of threads is to allow code to run in parallel, there are times where threads must stop and wait for other threads. For example, if two threads try to write to the same variable simultaneously, the result is undefined. The principle of forcing threads to wait for one another is called mutual exclusion. It is a common technique for protecting shared resources such as data.

Chart

Qt provides low-level primitives as well as high-level mechanisms for synchronizing threads.

Low-Level Synchronization Primitives

QMutex is the basic class for enforcing mutual exclusion. A thread locks a mutex in order to gain access to a shared resource. If a second thread tries to lock the mutex while it is already locked, the second thread will be put to sleep until the first thread completes its task and unlocks the mutex.

QReadWriteLock is similar to QMutex, except that it distinguishes between 'read' and 'write' access. When a piece of data is not being written to, it is safe for multiple threads to read from it simultaneously. A QMutex forces multiple readers to take turns to read shared data, but a QReadWriteLock allows simultaneous reading, thus improving parallelism.

QSemaphore is a generalization of QMutex that protects a certain number of identical resources. In contrast, a QMutex protects exactly one resource. The Semaphores Example shows a typical application of semaphores: synchronizing access to a circular buffer between a producer and a consumer.

QWaitCondition synchronizes threads not by enforcing mutual exclusion but by providing a condition variable. While the other primitives make threads wait until a resource is unlocked, QWaitCondition makes threads wait until a particular condition has been met. To allow the waiting threads to proceed, call wakeOne() to wake one randomly selected thread or wakeAll() to wake them all simultaneously. The Wait Conditions Example shows how to solve the producer-consumer problem using QWaitCondition instead of QSemaphore.

Note: Qt's synchronization classes rely on the use of properly aligned pointers. For instance, you cannot use packed classes with MSVC.

These synchronization classes can be used to make a method thread safe. However, doing so incurs a performance penalty, which is why most Qt methods are not made thread safe.

Risks

If a thread locks a resource but does not unlock it, the application may freeze because the resource will become permanently unavailable to other threads. This can happen, for example, if an exception is thrown and forces the current function to return without releasing its lock.

Another similar scenario is a deadlock. For example, suppose that thread A is waiting for thread B to unlock a resource. If thread B is also waiting for thread A to unlock a different resource, then both threads will end up waiting forever, so the application will freeze.

Convenience classes

QMutexLocker, QReadLocker and QWriteLocker are convenience classes that make it easier to use QMutex and QReadWriteLock. They lock a resource when they are constructed, and automatically unlock it when they are destroyed. They are designed to simplify code that use QMutex and QReadWriteLock, thus reducing the chances that a resource becomes permanently locked by accident.

High-Level Event Queues

Qt's event system is very useful for inter-thread communication. Every thread may have its own event loop. To call a slot (or any invokable method) in another thread, place that call in the target thread's event loop. This lets the target thread finish its current task before the slot starts running, while the original thread continues running in parallel.

To place an invocation in an event loop, make a queued signal-slot connection. Whenever the signal is emitted, its arguments will be recorded by the event system. The thread that the signal receiver lives in will then run the slot. Alternatively, call QMetaObject::invokeMethod() to achieve the same effect without signals. In both cases, a queued connection must be used because a direct connection bypasses the event system and runs the method immediately in the current thread.

Qt Slot Function Thread Chart

There is no risk of deadlocks when using the event system for thread synchronization, unlike using low-level primitives. However, the event system does not enforce mutual exclusion. If invokable methods access shared data, they must still be protected with low-level primitives.

Having said that, Qt's event system, along with implicitly shared data structures, offers an alternative to traditional thread locking. If signals and slots are used exclusively and no variables are shared between threads, a multithreaded program can do without low-level primitives altogether.

Qt Move To Thread

See also QThread::exec() and Threads and QObjects.

Qt Signals And Slots Between Threads

© 2020 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.

Copyright © 2022 mengerugram1981.netlify.com