30

Main (function main is there) thread of my program is reserved for non-GUI tasks. It calls a number of lengthy calculation functions. All implemented GUI's have been doing their work in a separate threads.

I'm now going to implement one more GUI using Qt. Qt documentation says all GUI related tasks should be done in main thread. In my case, inserting occasional QCoreApplication::processEvents() calls in main thread would be virtually useless due to great delays between them.

Is there any way to overcome this constraint of Qt? Is it impossible to do something non-GUI related in main thread of Qt program?

feedc0de
  • 3,646
  • 8
  • 30
  • 55
Basilevs
  • 22,440
  • 15
  • 57
  • 102

4 Answers4

33

No, you should be doing your calculations in a separate thread. As you already mentioned, there is a work-around available in QCoreApplication::processEvents(), but it sounds like you're unable to make that work for you.

If you don't want to have to do all the work of setting up a QThread and moving all your code, you may find that the QtConcurrent::run function is useful - it allows you to run a function asynchronously.

A few pointers: You should try and keep your main (GUI) thread as light as possible. Large amounts of IO or calculations should either be done asynchronously using QtConcurrent::run, or run inside a separate QThread. Depending on the complexity of your code, you may be able to get away with the QtConcurrent method.

Mat
  • 202,337
  • 40
  • 393
  • 406
Thomi
  • 11,647
  • 13
  • 72
  • 110
  • 1
    I dont see the big advantage of using QtConcurrent::run() instead of QThread. It is actually more work that way. Stick with QThread, its alot simpler to implement – yan bellavance Jan 28 '10 at 04:52
  • 3
    It depends on what you're doing and how your program is structured. If you need a permanent thread that must always be running then use QThread. If you need many small (often independent) tasks to run, and you don't care which ones are running at what time, then use QtConcurrent. – Thomi Jan 28 '10 at 08:17
  • Yeah I agree I might have been a little bit hard on it...like you say it depends on what you need. – yan bellavance Jan 28 '10 at 17:34
  • Disagree. Just create a QThread and **host** an QObject on it! After all, connect GUI code hosted on main() and QObject hosted on QThread by means of signals and slots. Overhead creating a thread for each task will be eliminated by simple, event-driven approach. – Brian Cannard Nov 01 '13 at 11:18
7

It's best to offload the long computations onto other threads so the main GUI thread remains responsive. The old-school uniprocessing way of doing things would be be to make sure your computations never run for too long without polling GUI event handler, but that doesn't scale to multi-cores.

Fortunately Qt has excellent threading support. In the past you'd have to roll-you-own system for e.g farming out tasks to a thread-pool using QThread, QMutex, QWaitCondition etc, but recent Qt releases have made things easier with higher level abstractions like QThreadPool, QtConcurrent::run and QFuture.

Mat
  • 202,337
  • 40
  • 393
  • 406
timday
  • 24,582
  • 12
  • 83
  • 135
0

I don't know how things will go if you call QApplication::exec() from another thread, which then becomes your gui thread. Just an idea.

(Let us know if it works, it'd be interesting...)

Macke
  • 24,812
  • 7
  • 82
  • 118
  • Why would you want to do this? If you need to do the work to spit your code up and run half of it on a different thread you may as well do it properly... or am I missing something? – Thomi Sep 06 '09 at 18:45
  • I'm not recommending, I'm just giving a tip on how to achieve precisely what the OP asked. The reason might be other libraries that require stuff done in main thread. (IIRC, OpenSG 1.x required rendering and loading to be done in same thread, so there we ended up with heavy OpenGL drawing in main thread (since we loaded all graphics in that thread). Not fun to have GUI running there as well, but that's how it went. (It's fixed in 2.x, IIRC). – Macke Sep 06 '09 at 19:14
  • 1
    You can do it, we just did it with a simple application and it worked. But when our program shuts down we get an invalid free() error or a double free() error. – dgrant Aug 23 '11 at 17:06
  • @dgrant: Cool! Then this could work as a temporary workaround until it is time to refactor properly. The free() error could be workaround by terminating the process. Of course, again, not recommended, but we've been forced to do something like that due to incompatibilities between Qt and .NET at at least one occasion. – Macke Aug 11 '14 at 19:36
  • This would work on Windows and Linux: [How to avoid Qt app.exec() blocking main thread](http://stackoverflow.com/a/22290909) – Basilevs Aug 16 '16 at 13:05
0

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')
user3650925
  • 173
  • 1
  • 10