How to Avoid Qt App.Exec() Blocking Main Thread

How to avoid Qt app.exec() blocking main thread

Most of the time, "main thread" == "GUI thread", so people use those terms interchangeably -- even the official documentation does that. I agree that it's confusing though, because they don't have to be the same.^ The actual rule is this:

GUI classes must only be accessed from the thread which instantiates QApplication/QGuiApplication

With a plugin like yours, here is what you need to do:

  1. Create a new std::thread (NOT a QThread)
  2. Run an init function in that thread. Let it instantiate your QApplication/QGuiApplication and start the event loop
  3. Ensure that all your GUI objects are accessed from that thread only.

Voila, you now have a GUI thread that is not your main thread.


^Note: It is a different story on Mac OS X. Due to restrictions in the Cocoa framework, the main thread MUST be the GUI thread. The steps I outlined above will work on Windows/Linux but not on Mac. For Mac, you need to inject your code into the main thread -- see Kuba Ober's comments below.

QApplication In Non-Main Thread

If you are using QThread then you already have normal Qt event loop and can just run exec() inside QThread::run() function. While you can't work with GUI objects outside of the main thread you still can interact with them through queued signal/slot connections. Maybe you can try to store pointer to the main thread QThread object and call QObject::moveToThread() to move your GUI objects to the main thread instead of moving QApplication into another thread.

I think it's not really good idea to try to go against toolkit with different kind of hacks and kluges.

QApplication in a non-main thread of second process with pyQt4: is this code legal, and if not, why does it work?

The concept of main thread is not clearly defined in Qt documentation. Actually, the main thread of a process (process that executes the Process.run function) can be different from the main Qt thread (thread that instantiates the first Qt object like a QApplication), although both "main" threads are often the same one.

Example of valid code structure:

function below will run in the process' non-main thread 'thread-1', that will become immediately Qt's main thread.

def startThread1():      
app = QApplication(sys.argv)
app.exec_() # enter event loop

code below run in process' main thread, not to be confused with the main Qt and unique GUI thread of the process.

thread1 = Thread(target=self.startThread1)
thread1.start()
input('I am busy until you press enter')


Related Topics



Leave a reply



Submit