Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtimer.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#include "qtimer.h"
7#include "qtimer_p.h"
9
13#include "qdeadlinetimer.h"
14#include "qmetaobject_p.h"
15#include "qobject_p.h"
16#include "qproperty_p.h"
17#include "qthread.h"
18
19#include <q26numeric.h> // for q26::staturate_cast
20
21using namespace std::chrono_literals;
22
24
26 = default;
27
28/*!
29 \class QTimer
30 \inmodule QtCore
31 \brief The QTimer class provides repetitive and single-shot timers.
32
33 \ingroup events
34
35
36 The QTimer class provides a high-level programming interface for
37 timers. To use it, create a QTimer, connect its timeout() signal
38 to the appropriate slots, and call start(). From then on, it will
39 emit the timeout() signal at constant intervals.
40
41 Example for a one second (1000 millisecond) timer (from the
42 \l{widgets/analogclock}{Analog Clock} example):
43
44 \snippet ../widgets/widgets/analogclock/analogclock.cpp 4
45 \snippet ../widgets/widgets/analogclock/analogclock.cpp 5
46 \snippet ../widgets/widgets/analogclock/analogclock.cpp 6
47
48 From then on, the \c update() slot is called every second.
49
50 You can set a timer to time out only once by calling
51 setSingleShot(true). You can also use the static
52 QTimer::singleShot() function to call a slot after a specified
53 interval:
54
55 \snippet timers/timers.cpp 3
56
57 In multithreaded applications, you can use QTimer in any thread
58 that has an event loop. To start an event loop from a non-GUI
59 thread, use QThread::exec(). Qt uses the timer's
60 \l{QObject::thread()}{thread affinity} to determine which thread
61 will emit the \l{QTimer::}{timeout()} signal. Because of this, you
62 must start and stop the timer in its thread; it is not possible to
63 start a timer from another thread.
64
65 As a special case, a QTimer with a timeout of 0 will time out as soon as
66 possible, though the ordering between zero timers and other sources of
67 events is unspecified. Zero timers can be used to do some work while still
68 providing a snappy user interface:
69
70 \snippet timers/timers.cpp 4
71 \snippet timers/timers.cpp 5
72 \snippet timers/timers.cpp 6
73
74 From then on, \c processOneThing() will be called repeatedly. It
75 should be written in such a way that it always returns quickly
76 (typically after processing one data item) so that Qt can deliver
77 events to the user interface and stop the timer as soon as it has done all
78 its work. This is the traditional way of implementing heavy work
79 in GUI applications, but as multithreading is nowadays becoming available on
80 more and more platforms, we expect that zero-millisecond
81 QTimer objects will gradually be replaced by \l{QThread}s.
82
83 \section1 Accuracy and Timer Resolution
84
85 The accuracy of timers depends on the underlying operating system
86 and hardware. Most platforms support a resolution of 1 millisecond,
87 though the accuracy of the timer will not equal this resolution
88 in many real-world situations.
89
90 The accuracy also depends on the \l{Qt::TimerType}{timer type}. For
91 Qt::PreciseTimer, QTimer will try to keep the accuracy at 1 millisecond.
92 Precise timers will also never time out earlier than expected.
93
94 For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
95 earlier than expected, within the margins for those types: 5% of the
96 interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
97
98 All timer types may time out later than expected if the system is busy or
99 unable to provide the requested accuracy. In such a case of timeout
100 overrun, Qt will emit timeout() only once, even if multiple timeouts have
101 expired, and then will resume the original interval.
102
103 \section1 Alternatives to QTimer
104
105 Qt 6.8 introduced QChronoTimer. The main difference between the two
106 classes, is that QChronoTimer supports a larger interval range and a
107 higher precision (\c std::chrono::nanoseconds). For QTimer the maximum
108 supported interval is ±24 days, whereas for QChronoTimer it is ±292
109 years (less chances of interger overflow with intervals longer than
110 \c std::numeric_limits<int>::max()). If you only need millisecond
111 resolution and ±24 days range, you can continue to use QTimer.
112
113 \include timers-common.qdocinc q-chrono-timer-alternatives
114
115 Some operating systems limit the number of timers that may be
116 used; Qt tries to work around these limitations.
117
118 \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
119 {Analog Clock}
120*/
121
122/*!
123 Constructs a timer with the given \a parent.
124*/
125
126QTimer::QTimer(QObject *parent)
127 : QObject(*new QTimerPrivate(this), parent)
128{
129 Q_ASSERT(d_func()->isQTimer);
130}
131
132
133/*!
134 Destroys the timer.
135*/
136
137QTimer::~QTimer()
138{
139 if (d_func()->isActive()) // stop running timer
140 stop();
141}
142
143
144/*!
145 \fn void QTimer::timeout()
146
147 This signal is emitted when the timer times out.
148
149 \sa interval, start(), stop()
150*/
151
152/*!
153 \property QTimer::active
154 \since 4.3
155
156 This boolean property is \c true if the timer is running; otherwise
157 false.
158*/
159
160/*!
161 \fn bool QTimer::isActive() const
162
163 Returns \c true if the timer is running; otherwise returns \c false.
164*/
165bool QTimer::isActive() const
166{
167 return d_func()->isActiveData.value();
168}
169
170QBindable<bool> QTimer::bindableActive()
171{
172 return QBindable<bool>(&d_func()->isActiveData);
173}
174
175/*!
176 \fn int QTimer::timerId() const
177
178 Returns the ID of the timer if the timer is running; otherwise returns
179 -1.
180*/
181int QTimer::timerId() const
182{
183 auto v = qToUnderlying(id());
184 return v == 0 ? -1 : v;
185}
186
187/*!
188 \since 6.8
189 Returns a Qt::TimerId representing the timer ID if the timer is running;
190 otherwise returns \c Qt::TimerId::Invalid.
191
192 \sa Qt::TimerId
193*/
194Qt::TimerId QTimer::id() const
195{
196 return d_func()->id;
197}
198
199/*! \overload start()
200
201 Starts or restarts the timer with the timeout specified in \l interval.
202
203//! [stop-restart-timer]
204 If the timer is already running, it will be
205 \l{QTimer::stop()}{stopped} and restarted. This will also change its id().
206//! [stop-restart-timer]
207
208//! [singleshot-activation]
209 If \l singleShot is true, the timer will be activated only once.
210//! [singleshot-activation]
211
212//! [eventloop-busy]
213 \note Keeping the event loop busy with a zero-timer is bound to
214 cause trouble and highly erratic behavior of the UI.
215//! [eventloop-busy]
216*/
217void QTimer::start()
218{
219 Q_D(QTimer);
220 if (d->isActive()) // stop running timer
221 stop();
222
223 Qt::TimerId newId{ QObject::startTimer(d->inter * 1ms, d->type) }; // overflow impossible
224 if (newId > Qt::TimerId::Invalid) {
225 d->id = newId;
226 d->isActiveData.notify();
227 }
228}
229
230/*!
231 Starts or restarts the timer with a timeout interval of \a msec
232 milliseconds.
233
234 This is equivalent to:
235
236 \code
237 timer.setInterval(msec);
238 timer.start();
239 \endcode
240
241 \include qtimer.cpp stop-restart-timer
242
243 \include qtimer.cpp singleshot-activation
244
245 \include timers-common.qdocinc negative-intervals-not-allowed
246
247 \include qtimer.cpp eventloop-busy
248*/
249void QTimer::start(int msec)
250{
251 start(msec * 1ms);
252}
253
254static int
255checkInterval(const char *caller, std::chrono::milliseconds interval)
256{
257 if (interval < 0ms) {
258 qWarning("%s: negative intervals aren't allowed; the interval will be set to 1ms.", caller);
259 return 1;
260 }
261
262 const auto msec = interval.count();
263 int ret = q26::saturating_cast<int>(msec);
264 if (ret != msec) {
265 qWarning("%s: interval exceeds maximum allowed interval, it will be clamped to "
266 "INT_MAX ms (about 24 days).", caller);
267 }
268 return ret;
269}
270
271/*!
272 \since 5.8
273 \overload
274
275 Starts or restarts the timer with a timeout of duration \a interval milliseconds.
276
277 This is equivalent to:
278
279 \code
280 timer.setInterval(interval);
281 timer.start();
282 \endcode
283
284 \include qtimer.cpp stop-restart-timer
285
286 \include qtimer.cpp singleshot-activation
287
288 \include timers-common.qdocinc negative-intervals-not-allowed
289
290 \include qtimer.cpp eventloop-busy
291*/
292void QTimer::start(std::chrono::milliseconds interval)
293{
294 Q_D(QTimer);
295
296 const int msec = checkInterval("QTimer::start", interval);
297 const bool intervalChanged = msec != d->inter;
298 d->inter.setValue(msec);
299 start();
300 if (intervalChanged)
301 d->inter.notify();
302}
303
304
305
306/*!
307 Stops the timer.
308
309 \sa start()
310*/
311
312void QTimer::stop()
313{
314 Q_D(QTimer);
315 if (d->isActive()) {
316 QObject::killTimer(d->id);
317 d->id = Qt::TimerId::Invalid;
318 d->isActiveData.notify();
319 }
320}
321
322
323/*!
324 \reimp
325*/
326void QTimer::timerEvent(QTimerEvent *e)
327{
328 Q_D(QTimer);
329 if (e->id() == d->id) {
330 if (d->single)
331 stop();
332 emit timeout(QPrivateSignal());
333 }
334}
335
336QAbstractEventDispatcher::Duration // statically asserts that Duration is nanoseconds
337QTimer::from_msecs(std::chrono::milliseconds ms)
338{
339 using Duration = QAbstractEventDispatcher::Duration;
340
341 using namespace std::chrono;
342 using ratio = std::ratio_divide<std::milli, Duration::period>;
343 static_assert(ratio::den == 1);
344
345 Duration::rep r;
346 if (qMulOverflow<ratio::num>(ms.count(), &r)) {
347 qWarning("QTimer::singleShot(std::chrono::milliseconds, ...): "
348 "interval argument overflowed when converted to nanoseconds.");
349 return Duration::max();
350 }
351 return Duration{r};
352}
353
354/*!
355 \internal
356
357 Implementation of the template version of singleShot
358
359 \a msec is the timer interval
360 \a timerType is the timer type
361 \a receiver is the receiver object, can be null. In such a case, it will be the same
362 as the final sender class.
363 \a slotObj the slot object
364*/
365void QTimer::singleShotImpl(std::chrono::nanoseconds ns, Qt::TimerType timerType,
366 const QObject *receiver,
367 QtPrivate::QSlotObjectBase *slotObj)
368{
369 Q_ASSERT_X(slotObj, "QTimer::singleShot", "Internal error, caller must not pass null slotObj");
370 if (ns == 0ns) {
371 bool deleteReceiver = false;
372 // Optimize: set a receiver context when none is given, such that we can use
373 // QMetaObject::invokeMethod which is more efficient than going through a timer.
374 // We need a QObject living in the current thread. But the QThread itself lives
375 // in a different thread - with the exception of the main QThread which lives in
376 // itself. And QThread::currentThread() is among the few QObjects we know that will
377 // most certainly be there. Note that one can actually call singleShot before the
378 // QApplication is created!
379 if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
380 // reuse main thread as context object
381 receiver = QThread::currentThread();
382 } else if (!receiver) {
383 // Create a receiver context object on-demand. According to the benchmarks,
384 // this is still more efficient than going through a timer.
385 receiver = new QObject;
386 deleteReceiver = true;
387 }
388
389 auto h = QtPrivate::invokeMethodHelper({});
390 QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
391 Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
392 h.metaTypes.data());
393
394 if (deleteReceiver)
395 const_cast<QObject *>(receiver)->deleteLater();
396 return;
397 }
398
399 (void) new QSingleShotTimer(ns, timerType, receiver, slotObj);
400}
401
402/*!
403 \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
404 \reentrant
405 \deprecated [6.8] Use the chrono overloads.
406 This static function calls a slot after a given time interval.
407
408 It is very convenient to use this function because you do not need
409 to bother with a \l{QObject::timerEvent()}{timerEvent} or
410 create a local QTimer object.
411
412 Example:
413 \snippet code/src_corelib_kernel_qtimer.cpp 0
414
415 This sample program automatically terminates after 10 minutes
416 (600,000 milliseconds).
417
418 The \a receiver is the receiving object and the \a member is the
419 slot. The time interval is \a msec milliseconds.
420
421 \include timers-common.qdocinc negative-intervals-not-allowed
422
423 \sa start()
424*/
425
426/*!
427 \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
428 \overload
429 \reentrant
430 \deprecated [6.8] Use the chrono overloads.
431 This static function calls a slot after a given time interval.
432
433 It is very convenient to use this function because you do not need
434 to bother with a \l{QObject::timerEvent()}{timerEvent} or
435 create a local QTimer object.
436
437 The \a receiver is the receiving object and the \a member is the slot. The
438 time interval is \a msec milliseconds. The \a timerType affects the
439 accuracy of the timer.
440
441 \include timers-common.qdocinc negative-intervals-not-allowed
442
443 \sa start()
444*/
445
446void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType,
447 const QObject *receiver, const char *member)
448{
449 if (ns < 0ns) {
450 qWarning("QTimer::singleShot: negative intervals aren't allowed; the "
451 "interval will be set to 1ms.");
452 ns = 1ms;
453 }
454 if (receiver && member) {
455 if (ns == 0ns) {
456 // special code shortpath for 0-timers
457 const char* bracketPosition = strchr(member, '(');
458 if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
459 qWarning("QTimer::singleShot: Invalid slot specification");
460 return;
461 }
462 const auto methodName = QByteArrayView(member + 1, // extract method name
463 bracketPosition - 1 - member).trimmed();
464 QMetaObject::invokeMethod(const_cast<QObject *>(receiver), methodName.toByteArray().constData(),
465 Qt::QueuedConnection);
466 return;
467 }
468 (void) new QSingleShotTimer(ns, timerType, receiver, member);
469 }
470}
471
472/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, const QObject *context, Functor &&functor)
473 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor)
474 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Functor &&functor)
475 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor)
476 \since 5.4
477
478 \reentrant
479 This static function calls \a functor after \a interval.
480
481 It is very convenient to use this function because you do not need
482 to bother with a \l{QObject::timerEvent()}{timerEvent} or
483 create a local QTimer object.
484
485 If \a context is specified, then the \a functor will be called only if the
486 \a context object has not been destroyed before the interval occurs. The functor
487 will then be run the thread of \a context. The context's thread must have a
488 running Qt event loop.
489
490 If \a functor is a member
491 function of \a context, then the function will be called on the object.
492
493 The \a interval parameter can be an \c int (interpreted as a millisecond
494 count) or a \c std::chrono type that implicitly converts to nanoseconds.
495
496 \include timers-common.qdocinc negative-intervals-not-allowed
497
498 \note In Qt versions prior to 6.8, the chrono overloads took chrono::milliseconds,
499 not chrono::nanoseconds. The compiler will automatically convert for you,
500 but the conversion may overflow for extremely large milliseconds counts.
501
502 \sa start()
503*/
504
505/*!
506 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member)
507 \since 5.8
508 \overload
509 \reentrant
510
511 This static function calls a slot after a given time interval.
512
513 It is very convenient to use this function because you do not need
514 to bother with a \l{QObject::timerEvent()}{timerEvent} or
515 create a local QTimer object.
516
517 The \a receiver is the receiving object and the \a member is the slot. The
518 time interval is given in the duration object \a nsec.
519
520 \include timers-common.qdocinc negative-intervals-not-allowed
521
522//! [qtimer-ns-overflow]
523 \note In Qt versions prior to 6.8, this function took chrono::milliseconds,
524 not chrono::nanoseconds. The compiler will automatically convert for you,
525 but the conversion may overflow for extremely large milliseconds counts.
526//! [qtimer-ns-overflow]
527
528 \sa start()
529*/
530
531/*!
532 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member)
533 \since 5.8
534 \overload
535 \reentrant
536
537 This static function calls a slot after a given time interval.
538
539 It is very convenient to use this function because you do not need
540 to bother with a \l{QObject::timerEvent()}{timerEvent} or
541 create a local QTimer object.
542
543 The \a receiver is the receiving object and the \a member is the slot. The
544 time interval is given in the duration object \a nsec. The \a timerType affects the
545 accuracy of the timer.
546
547
548 \include timers-common.qdocinc negative-intervals-not-allowed
549
550 \include qtimer.cpp qtimer-ns-overflow
551
552 \sa start()
553*/
554
555/*!
556 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
557 \since 5.12
558
559 Creates a connection from the timer's timeout() signal to \a slot.
560 Returns a handle to the connection.
561
562 This method is provided for convenience. It's equivalent to calling:
563 \code
564 QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
565 \endcode
566
567 \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
568 defined, instead use the callOnTimeout() overload that takes a context object.
569
570 \sa QObject::connect(), timeout()
571*/
572
573/*!
574 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
575 \since 5.12
576 \overload callOnTimeout()
577
578 Creates a connection from the timeout() signal to \a slot to be placed in a specific
579 event loop of \a context, and returns a handle to the connection.
580
581 This method is provided for convenience. It's equivalent to calling:
582 \code
583 QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
584 \endcode
585
586 \sa QObject::connect(), timeout()
587*/
588
589/*!
590 \fn std::chrono::milliseconds QTimer::intervalAsDuration() const
591 \since 5.8
592
593 Returns the interval of this timer as a \c std::chrono::milliseconds object.
594
595 \sa interval
596*/
597
598/*!
599 \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
600 \since 5.8
601
602 Returns the time remaining in this timer object as a \c
603 std::chrono::milliseconds object. If this timer is due or overdue, the
604 returned value is \c std::chrono::milliseconds::zero(). If the remaining
605 time could not be found or the timer is not running, this function returns a
606 negative duration.
607
608 \sa remainingTime()
609*/
610
611/*!
612 \property QTimer::singleShot
613 \brief whether the timer is a single-shot timer
614
615 A single-shot timer fires only once, non-single-shot timers fire
616 every \l interval milliseconds.
617
618 The default value for this property is \c false.
619
620 \sa interval, singleShot()
621*/
622void QTimer::setSingleShot(bool singleShot)
623{
624 d_func()->single = singleShot;
625}
626
627bool QTimer::isSingleShot() const
628{
629 return d_func()->single;
630}
631
632QBindable<bool> QTimer::bindableSingleShot()
633{
634 return QBindable<bool>(&d_func()->single);
635}
636
637/*!
638 \property QTimer::interval
639 \brief the timeout interval in milliseconds
640
641 The default value for this property is 0. A QTimer with a timeout
642 interval of 0 will time out as soon as all the events in the window
643 system's event queue have been processed.
644
645 \include qtimer.cpp eventloop-busy
646
647 Setting the interval of a running timer will change the interval,
648 stop() and then start() the timer, and acquire a new id().
649 If the timer is not running, only the interval is changed.
650
651 \include timers-common.qdocinc negative-intervals-not-allowed
652
653 \sa singleShot
654*/
655void QTimer::setInterval(int msec)
656{
657 setInterval(std::chrono::milliseconds{msec});
658}
659
660void QTimer::setInterval(std::chrono::milliseconds interval)
661{
662 Q_D(QTimer);
663
664 const int msec = checkInterval("QTimer::setInterval", interval);
665 d->inter.removeBindingUnlessInWrapper();
666 const bool intervalChanged = msec != d->inter.valueBypassingBindings();
667 d->inter.setValueBypassingBindings(msec);
668 if (d->isActive()) { // create new timer
669 QObject::killTimer(d->id); // restart timer
670 Qt::TimerId newId{ QObject::startTimer(msec * 1ms, d->type) }; // overflow impossible
671 if (newId > Qt::TimerId::Invalid) {
672 // Restarted successfully. No need to update the active state.
673 d->id = newId;
674 } else {
675 // Failed to start the timer.
676 // Need to notify about active state change.
677 d->id = Qt::TimerId::Invalid;
678 d->isActiveData.notify();
679 }
680 }
681 if (intervalChanged)
682 d->inter.notify();
683}
684
685int QTimer::interval() const
686{
687 return d_func()->inter;
688}
689
690QBindable<int> QTimer::bindableInterval()
691{
692 return QBindable<int>(&d_func()->inter);
693}
694
695/*!
696 \property QTimer::remainingTime
697 \since 5.0
698 \brief the remaining time in milliseconds
699
700 Returns the timer's remaining value in milliseconds left until the timeout.
701 If the timer is inactive, the returned value will be -1. If the timer is
702 overdue, the returned value will be 0.
703
704 \sa interval
705*/
706int QTimer::remainingTime() const
707{
708 Q_D(const QTimer);
709 if (d->isActive()) {
710 using namespace std::chrono;
711 auto remaining = QAbstractEventDispatcher::instance()->remainingTime(d->id);
712 const auto msec = ceil<milliseconds>(remaining).count();
713 const int ret = q26::saturating_cast<int>(msec);
714 Q_ASSERT(ret == msec); // cannot overflow because the interval is clamped before it's set
715 return ret;
716 }
717
718 return -1;
719}
720
721/*!
722 \property QTimer::timerType
723 \brief controls the accuracy of the timer
724
725 The default value for this property is \c Qt::CoarseTimer.
726
727 \sa Qt::TimerType
728*/
729void QTimer::setTimerType(Qt::TimerType atype)
730{
731 d_func()->type = atype;
732}
733
734Qt::TimerType QTimer::timerType() const
735{
736 return d_func()->type;
737}
738
739QBindable<Qt::TimerType> QTimer::bindableTimerType()
740{
741 return QBindable<Qt::TimerType>(&d_func()->type);
742}
743
744QT_END_NAMESPACE
745
746#include "moc_qtimer.cpp"
~QTimerPrivate() override
static int checkInterval(const char *caller, std::chrono::milliseconds interval)
Definition qtimer.cpp:255