Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qchronotimer.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
"qchronotimer.h"
7
#
include
"qtimer_p.h"
8
#
include
"qsingleshottimer_p.h"
9
10
#
include
"qabstracteventdispatcher.h"
11
#
include
"qcoreapplication.h"
12
#
include
"qcoreapplication_p.h"
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
using
namespace
std::chrono_literals;
20
21
QT_BEGIN_NAMESPACE
22
23
/*!
24
\class QChronoTimer
25
\inmodule QtCore
26
\since 6.8
27
\ingroup events
28
29
\brief The QChronoTimer class provides repetitive and single-shot timers.
30
31
The QChronoTimer class provides a high-level programming interface for
32
timers. To use it, create a QChronoTimer, either passing the interval to the
33
constructor, or setting it after construction using setInterval(), connect
34
its timeout() signal to the appropriate slots, and call start(). From then
35
on, it will emit the timeout() signal at constant intervals. For example:
36
37
\snippet timers/timers.cpp qchronotimer-interval-in-ctor
38
\snippet timers/timers.cpp qchronotimer-setinterval
39
40
You can set a timer to time out only once by calling setSingleShot(true).
41
42
\note QChronoTimer has no singleShot() static methods, as the ones on
43
QTimer already work with chrono types and nanoseconds resolution.
44
45
In multithreaded applications, you can use QChronoTimer in any thread
46
that has an event loop. To start an event loop from a non-GUI
47
thread, use QThread::exec(). Qt uses the timer's
48
\l{QObject::thread()}{thread affinity} to determine which thread
49
will emit the \l{QChronoTimer::}{timeout()} signal. Because of this, you
50
must start and stop the timer in its thread; it is not possible to
51
start a timer from another thread.
52
53
As a special case, a QChronoTimer with a timeout of \c 0ns will time out
54
as soon as possible, though the ordering between zero timers and other
55
sources of events is unspecified. Zero timers can be used to do some
56
work while still providing a responsive user interface:
57
58
\snippet timers/timers.cpp zero-timer
59
60
From then on, \c processOneThing() will be called repeatedly. It should
61
be written in such a way that it always returns quickly (for example,
62
after processing one data item) so that Qt can deliver events to the user
63
interface and stop the timer as soon as it has done all its work. This
64
is the traditional way of implementing heavy work in GUI applications,
65
but as multithreading is becoming available on more platforms, a modern
66
alternative is doing the heavy work in a thread other than the GUI (main)
67
thread. Qt has the QThread class, which can be used to achieve that.
68
69
\section1 Accuracy and Timer Resolution
70
71
The accuracy of timers depends on the underlying operating system and
72
hardware. Most platforms support requesting nano-second precision for
73
timers (for example, libc's \c nanosleep), though the accuracy of the
74
timer will not equal this resolution in many real-world situations.
75
76
You can set the \l{Qt::TimerType}{timer type} to tell QChronoTimer which
77
precision to request from the system.
78
79
For Qt::PreciseTimer, QChronoTimer will try to keep the precision at
80
\c 1ns. Precise timers will never time out earlier than expected.
81
82
For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QChronoTimer may wake
83
up earlier than expected, within the margins for those types:
84
\list
85
\li 5% of the interval for Qt::CoarseTimer
86
\li \c 500ms for Qt::VeryCoarseTimer
87
\endlist
88
89
All timer types may time out later than expected if the system is busy or
90
unable to provide the requested accuracy. In such a case of timeout
91
overrun, Qt will emit timeout() only once, even if multiple timeouts have
92
expired, and then will resume the original interval.
93
94
\section1 Alternatives to QChronoTimer
95
96
QChronoTimer provides nanosecond resolution and a ±292 years range
97
(less chances of integer overflow if the interval is longer than \c
98
std::numeric_limits<int>::max()). If you only need millisecond resolution
99
and ±24 days range, you can continue to use the classical QTimer class
100
101
\include timers-common.qdocinc q-chrono-timer-alternatives
102
103
Some operating systems limit the number of timers that may be used;
104
Qt does its best to work around these limitations.
105
106
\sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
107
{Analog Clock}
108
*/
109
110
/*!
111
Constructs a timer with the given \a parent, using the default interval,
112
\c 0ns.
113
*/
114
QChronoTimer::QChronoTimer(QObject *parent)
115
: QChronoTimer(0ns, parent)
116
{
117
}
118
119
/*!
120
Constructs a timer with the given \a parent, using an interval of \a nsec.
121
*/
122
QChronoTimer::QChronoTimer(std::chrono::nanoseconds nsec, QObject *parent)
123
: QObject(*
new
QTimerPrivate(nsec,
this
), parent)
124
{
125
Q_ASSERT(!d_func()->isQTimer);
126
}
127
128
/*!
129
Destroys the timer.
130
*/
131
QChronoTimer::~QChronoTimer()
132
{
133
if
(d_func()->isActive())
// stop running timer
134
stop();
135
}
136
137
/*!
138
\fn void QChronoTimer::timeout()
139
140
This signal is emitted when the timer times out.
141
142
\sa interval, start(), stop()
143
*/
144
145
/*!
146
\property QChronoTimer::active
147
148
This boolean property is \c true if the timer is running; otherwise
149
\c false.
150
*/
151
152
/*!
153
Returns \c true if the timer is running; otherwise returns \c false.
154
*/
155
bool
QChronoTimer::isActive()
const
156
{
157
return
d_func()->isActiveData.value();
158
}
159
160
QBindable<
bool
> QChronoTimer::bindableActive()
161
{
162
return
QBindable<
bool
>(&d_func()->isActiveData);
163
}
164
165
/*!
166
Returns a Qt::TimerId representing the timer ID if the timer is running;
167
otherwise returns \c Qt::TimerId::Invalid.
168
169
\sa Qt::TimerId
170
*/
171
Qt::TimerId QChronoTimer::id()
const
172
{
173
return
d_func()->id;
174
}
175
176
/*! \overload start()
177
178
Starts or restarts the timer with the timeout specified in \l interval.
179
180
//! [stop-restart-timer]
181
If the timer is already running, it will be
182
\l{QChronoTimer::stop()}{stopped} and restarted. This will also change its
183
id().
184
//! [stop-restart-timer]
185
186
If \l singleShot is true, the timer will be activated only once.
187
*/
188
void
QChronoTimer::start()
189
{
190
auto
*d = d_func();
191
if
(d->isActive())
// stop running timer
192
stop();
193
const
auto
id = Qt::TimerId{QObject::startTimer(d->intervalDuration, d->type)};
194
if
(id != Qt::TimerId::Invalid) {
195
d->id = id;
196
d->isActiveData.notify();
197
}
198
}
199
200
/*!
201
Stops the timer.
202
203
\sa start()
204
*/
205
void
QChronoTimer::stop()
206
{
207
auto
*d = d_func();
208
if
(d->isActive()) {
209
QObject::killTimer(d->id);
210
d->id = Qt::TimerId::Invalid;
211
d->isActiveData.notify();
212
}
213
}
214
215
/*!
216
\reimp
217
*/
218
void
QChronoTimer::timerEvent(QTimerEvent *e)
219
{
220
auto
*d = d_func();
221
if
(e->id() == d->id) {
222
if
(d->single)
223
stop();
224
Q_EMIT timeout(QPrivateSignal());
225
}
226
}
227
228
/*!
229
\fn template <typename Functor> QMetaObject::Connection QChronoTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
230
\overload callOnTimeout()
231
232
Creates a connection from the timeout() signal to \a slot to be placed in a
233
specific event loop of \a context, with connection type \a connectionType,
234
and returns a handle to the connection.
235
236
This method is provided as a convenience. It's equivalent to calling:
237
\code
238
QObject::connect(timer, &QChronoTimer::timeout, context, slot, connectionType);
239
\endcode
240
241
\sa QObject::connect(), timeout()
242
*/
243
244
/*!
245
\property QChronoTimer::singleShot
246
\brief Whether the timer is a single-shot timer
247
248
A single-shot timer fires only once, non-single-shot timers fire every
249
\l interval.
250
251
The default value for this property is \c false.
252
253
\sa interval
254
*/
255
void
QChronoTimer::setSingleShot(
bool
singleShot)
256
{
257
d_func()->single = singleShot;
258
}
259
260
bool
QChronoTimer::isSingleShot()
const
261
{
262
return
d_func()->single;
263
}
264
265
QBindable<
bool
> QChronoTimer::bindableSingleShot()
266
{
267
return
QBindable<
bool
>(&d_func()->single);
268
}
269
270
/*!
271
\property QChronoTimer::interval
272
\brief The timeout interval
273
274
The default value for this property is \c 0ns.
275
276
A QChronoTimer with a timeout of \c 0ns will time out as soon as
277
possible, though the ordering between zero timers and other sources of
278
events is unspecified.
279
280
Setting the interval of a running timer will change the interval,
281
stop() and then start() the timer, and acquire a new id().
282
If the timer is not running, only the interval is changed.
283
284
\include timers-common.qdocinc negative-intervals-not-allowed
285
286
\sa singleShot
287
*/
288
void
QChronoTimer::setInterval(std::chrono::nanoseconds nsec)
289
{
290
if
(nsec < 0ns) {
291
qWarning(
"QChronoTimer::setInterval: negative intervals aren't allowed; the "
292
"interval will be set to 1ms."
);
293
nsec = 1ms;
294
}
295
296
auto
*d = d_func();
297
d->intervalDuration.removeBindingUnlessInWrapper();
298
const
bool
intervalChanged = nsec != d->intervalDuration.valueBypassingBindings();
299
d->intervalDuration.setValueBypassingBindings(nsec);
300
if
(d->isActive()) {
// Create new timer
301
QObject::killTimer(d->id);
// Restart timer
302
const
auto
newId = Qt::TimerId{QObject::startTimer(nsec, d->type)};
303
if
(newId != Qt::TimerId::Invalid) {
304
// Restarted successfully. No need to update the active state.
305
d->id = newId;
306
}
else
{
307
// Failed to start the timer.
308
// Need to notify about active state change.
309
d->id = Qt::TimerId::Invalid;
310
d->isActiveData.notify();
311
}
312
}
313
if
(intervalChanged)
314
d->intervalDuration.notify();
315
}
316
317
std::chrono::nanoseconds QChronoTimer::interval()
const
318
{
319
return
d_func()->intervalDuration.value();
320
}
321
322
QBindable<std::chrono::nanoseconds> QChronoTimer::bindableInterval()
323
{
324
return
{&d_func()->intervalDuration};
325
}
326
327
/*!
328
\property QChronoTimer::remainingTime
329
\brief The remaining time
330
331
Returns the remaining duration until the timeout.
332
333
If the timer is inactive, the returned duration will be negative.
334
335
If the timer is overdue, the returned duration will be \c 0ns.
336
337
\sa interval
338
*/
339
std::chrono::nanoseconds QChronoTimer::remainingTime()
const
340
{
341
if
(isActive())
342
return
QAbstractEventDispatcher::instance()->remainingTime(d_func()->id);
343
return
std::chrono::nanoseconds::min();
344
}
345
346
/*!
347
\property QChronoTimer::timerType
348
\brief Controls the accuracy of the timer
349
350
The default value for this property is \c Qt::CoarseTimer.
351
352
\sa Qt::TimerType
353
*/
354
void
QChronoTimer::setTimerType(Qt::TimerType atype)
355
{
356
d_func()->type = atype;
357
}
358
359
Qt::TimerType QChronoTimer::timerType()
const
360
{
361
return
d_func()->type;
362
}
363
364
QBindable<Qt::TimerType> QChronoTimer::bindableTimerType()
365
{
366
return
{&d_func()->type};
367
}
368
369
QT_END_NAMESPACE
370
371
#
include
"moc_qchronotimer.cpp"
qtbase
src
corelib
kernel
qchronotimer.cpp
Generated on
for Qt by
1.18.0