Does a QTimer object run in a separate thread? What is its mechanism?

Related searches

When I create a QTimer object in Qt 5, and start it using the start() member function, is a separate thread created that keeps track of the time and calls the timeout() function at regular intervals?

For example,

QTimer *timer = new QTimer;
timer->start(10);
connect(timer,SIGNAL(timeout()),someObject,SLOT(someFunction()));

Here, how does the program know when timeout() occurs? I think it would have to run in a separate thread, as I don't see how a sequential program could keep track of the time and continue its execution simultaneously. However, I have been unable to find any information regarding this either in the Qt documentation or anywhere else to confirm this.

I have read the official documentation, and certain questions on StackOverflow such as this and this seem very related, but I could not get my answer through them.

Could anyone explain the mechanism through which a QTimer object works?

On searching further, I found that as per this answer by Bill, it is mentioned that

Events are delivered asynchronously by the OS, which is why it appears that there's something else going on. There is, but not in your program.

Does it mean that timeout() is handled by the OS? Is there some hardware that keeps track of the time and send interrupts at appropriate intervals? But if this is the case, as many timers can run simultaneously and independently, how can each timer be separately tracked?

What is the mechanism?

Thank you.

When I create a QTimer object in Qt 5, and start it using the start() member function, is a separate thread created that keeps track of the time and calls the timeout() function at regular intervals?

No; creating a separate thread would be expensive and it isn't necessary, so that isn't how QTimer is implemented.

Here, how does the program know when timeout() occurs?

The QTimer::start() method can call a system time function (e.g. gettimeofday() or similar) to find out (to within a few milliseconds) what the time was that start() was called. It can then add ten milliseconds (or whatever value you specified) to that time and now it has a record indicating when the timeout() signal is supposed to be emitted next.

So having that information, what does it then do to make sure that happens?

The key fact to know is that QTimer timeout-signal-emission only works if/when your Qt program is executing inside Qt's event loop. Just about every Qt program will have something like this, usually near the bottom its main() function:

QApplication app(argc, argv);
[...]
app.exec();

Note that in a typical application, almost all of the application's time will be spent inside that exec() call; that is to say, the app.exec() call will not return until it's time for the application to exit.

So what is going on inside that exec() call while your program is running? With a big complex library like Qt it's necessarily complicated, but it's not too much of a simplification to say that it's running an event loop that looks conceptually something like this:

 while(1)
 {
     SleepUntilThereIsSomethingToDo();  // not a real function name!
     DoTheThingsThatNeedDoingNow();     // this is also a name I made up
     if (timeToQuit) break;
 }

So when your app is idle, the process will be put to sleep inside the SleepUntilThereIsSomethingToDo() call, but as soon as an event arrives that needs handling (e.g. the user moves the mouse, or presses a key, or data arrives on a socket, or etc), SleepUntilThereIsSomethingToDo() will return and then the code to respond to that event will be executed, resulting in the appropriate action such as the widgets updating or the timeout() signal being called.

So how does SleepUntilThereIsSomethingToDo() know when it is time to wake up and return? This will vary greatly depending on what OS you are running on, since different OS's have different APIs for handling this sort of thing, but a classic UNIX-y way to implement such a function would be with the POSIX select() call:

int select(int nfds, 
           fd_set *readfds, 
           fd_set *writefds,
           fd_set *exceptfds, 
           struct timeval *timeout);

Note that select() takes three different fd_set arguments, each of which can specify a number of file descriptors; by passing in the appropriate fd_set objects to those arguments you can cause select() to wake up the instant an I/O operations becomes possible on any one of a set of file descriptors you care to monitor, so that your program can then handle the I/O without delay. However, the interesting part for us is the final argument, which is a timeout-argument. In particular, you can pass in a struct timeval object here that says to select(): "If no I/O events have occurred after (this many) microseconds, then you should just give up and return anyway".

That turns out to be very useful, because by using that parameter, the SleepUntilThereIsSomethingToDo() function can do something like this (pseudocode):

void SleepUntilThereIsSomethingToDo()
{
   struct timeval now = gettimeofday();  // get the current time
   struct timeval nextQTimerTime = [...];  // time at which we want to emit a timeout() signal, as was calculated earlier inside QTimer::start()
   struct timeval maxSleepTimeInterval = (nextQTimerTime-now);
   select([...], &maxSleepTimeInterval);  // sleep until the appointed time (or until I/O arrives, whichever comes first)
}

void DoTheThingsThatNeedDoingNow()
{
   // Is it time to emit the timeout() signal yet?
   struct timeval now = gettimeofday();
   if (now >= nextQTimerTime) emit timeout();

   [... do any other stuff that might need doing as well ...]
}   

Hopefully that makes sense, and you can see how the event loop uses select()'s timeout argument to allow it to wake up and emit the timeout() signal at (approximately) the time that it had previously calculated when you called start().

Btw if the app has more than one QTimer active simultaneously, that's no problem; in that case, SleepUntilThereIsSomethingToDo() just needs to iterate over all of the active QTimers to find the one with the smallest next-timeout-time stamp, and use only that minimum timestamp for its calculation of the maximum time-interval that select() should be allowed to sleep for. Then after select() returns, DoTheThingsThatNeedDoingNow() also iterates over the active timers and emits a timeout signal only for those whose next-timeout-time stamp is not greater than the current time. The event-loop repeats (as quickly or as slowly as necessary) to give a semblance of multithreaded behavior without actually requiring multiple threads.

Threads and QObjects, For this mechanism to work, the application must run in an event loop. a QTimerEvent, and the flow of control leaves the event loop until the timer Qt uses the object's thread affinity to determine which thread will deliver the QTimerEvent. Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread. You must ensure that all objects created in a thread are deleted before you delete the QThread.

Looking at the documentation about timers and at the source code of QTimer and QObject we can see that the timer is running in the thread/event loop that is assigned to the object. From the doc:

For QTimer to work, you must have an event loop in your application; that is, you must call QCoreApplication::exec() somewhere. Timer events will be delivered only while the event loop is running.

In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.

Internally, QTimer simply uses the QObject::startTimer method to fire after a certain amount of time. This one itself somehow tells the thread it's running on to fire after the amount of time.

So your program is fine running continously and keeping track of the timers as long as you don't block your event queue. If you are worried of your timer being not 100% accurate try to move long-running callbacks out of the event queue in their own thread, or use a different event queue for the timers.

Timers, These threads share the process' resources but are able to execute independently. Specifically, the tasks that are not using signal/slot mechanism during the task execution. Use: Worker objects moved to + QThread. logEventCore function will be likely executing in different threads from call to call. Does a QTimer object run in a separate thread? What is its, When I create a QTimer object in Qt 5, and start it using the start() member function, is a separate thread created that keeps track of the time and  The context's thread must have a running Qt event loop. Note: This function is reentrant. This function was introduced in Qt 5.4.

QTimer object registers itself into EventDispatcher (QAbstractEventDispatcher) which than takes care to send events of type QTimerEvent every time there is timeout for a particular registered QTimer. For example, on GNU/Linux there is a private implementation of QAbstractEventDispatcher called QEventDispatcherUNIXPrivate that makes calculations taking in consideration the platform api for the time. The QTimerEvent are sent from QEventDispatcherUNIXPrivate into the queue of the event loop of the same thread where QTimer object belongs, i.e. was created.

QEventDispatcherUNIXPrivate doesn't fire a QTimerEvent because of some OS system event or clock, but because it periodically checkes the timeout when processEvents is called by the thread event loop where QTimer lives too. Se here: https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp.html#_ZN27QEventDispatcherUNIXPrivateC1Ev

Qt Multithreading in C++: The Missing Article, The biggest dos and don'ts for multi-threading in Qt Either create it as an automatic variable inside the QThread's run() method, connect problems, protect them with appropriate synchronization mechanisms. You can only call moveToThread() on an object from the thread the object has affinity with. It is very convenient to use this function because you do not need to bother with a timerEvent or create a local QTimer object. The time interval is msec milliseconds. The timerType affects the accuracy of the timer. If context is destroyed before the interval occurs, the method will not be called. The function will be run in the thread of context. The context's thread must have a running Qt event loop.

The Eight Rules of Multithreaded Qt – KDAB, This is possible because each thread is allowed to have its own event loop. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket Specifically, this applies to the timer mechanism and the network module. This can be done easily by creating the objects on the stack in your run() implementation. In multithreaded applications, you can use the timer mechanism in any thread that has an event loop. To start an event loop from a non-GUI thread, use exec (). Qt uses the object’s thread affinity to determine which thread will deliver the QTimerEvent.

Threads and QObjects, QTimer only works if the Qt event loop is running; it can't/won't work while your thread is stuck inside your own while() loop, because that prevents the Qt event loop from executing events. See details here: stackoverflow.com/questions/42279360/…

Qt uses the object's thread affinity to determine which thread will deliver the QTimerEvent. Because of this, you must start and stop all timers in the object's thread; it is not possible to start timers for objects in another thread.

Comments
  • Thank you very much! That was very helpful. I have one query - in the function SleepUntilThereIsSomethingToDo(), the function returns early if some input needs to be handled. If if (now >= nextQTimerTime) is not yet true, then the timeout will not be emitted in DoTheThingsThatNeedDoingNow(). Later, when back in SleepUntilThereIsSomethingToDo(), the timer is reset. So isn't one timeout() skipped here? Or have I misunderstood? Thank you.
  • The timeout interval is recalculated for every call to SleepUntil(), but the timer isn't reset and the timeout isn't skipped. For example: Let's say at 2PM you call QTimer::start() and set the QTimer's interval to one hour. In the next call to SleepUntil() the timeout is calculated to be (3PM-2PM = 1 hour). But at 2:30PM some input comes in, so select() returns and the input gets handled. Now SleepUntil() gets called again, and calculates the new timeout to be (3PM-2:30PM=30 minutes). So (assuming no further input), it will still wake up and emit the signal at 3PM.
  • So does it mean that nextQTimerTime is stored somewhere else, accessible to both functions?
  • Yes, most likely each QTimer stores its own nextQTimerTime as a private variable somewhere inside the QTimer object, and the event loop looks at all the QTimer objects to find the smallest nextQTimerTime value amongst all of them, and uses that. (Probably this is further optimized by the use of a priority queue or similar data structure, but I haven't checked to be certain)
  • @k_kaz that is correct -- they all run in the same thread (by default anyway), so unless you are explicitly moving the QTimer objects to other threads, you are guaranteed that the slot calls will happen sequentially, so no synchronization is needed on your part.
  • Thank you. But how can the "flow of control" of the program do two things in a single thread - sequential execution of statements, as well as keep track of the time? Secondly, what is the role of the event loop in this?
  • @GoodDeeds To answer your question about your flow control you need to tell us what your application is doing. But I can't tell you how the timer is implemented itself - I could think of a) they are comparing current time to the time that should fire or b) use some hardware/operating system interrupt feature.
  • Thank you. I found this answer stackoverflow.com/a/1472579/5987698 (added to my question as well) that seems to give an insight in the second part of the comment - seems like (b) is true. But is it so? Also, if it worked as mentioned in (a), wouldn't some thread have to keep checking the time periodically? Wouldn't this cause inaccuracies?
  • @GoodDeeds If you remember the time of the last shot and compare it to the one of the next shot you'll see that there are a lot of inaccuracies and I don't think that there's an easy way of getting rid of them. But the average is pretty close to what you want and most applications are fine to be called in a somewhat accurate interval. To get the most accuracy you need to look into low-level functions that handle the timeout