1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QSEMAPHORE_H |
5 | #define QSEMAPHORE_H |
6 | |
7 | #include <QtCore/qglobal.h> |
8 | #include <QtCore/qdeadlinetimer.h> |
9 | |
10 | #include <chrono> |
11 | |
12 | QT_REQUIRE_CONFIG(thread); |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | class QSemaphorePrivate; |
17 | class Q_CORE_EXPORT QSemaphore |
18 | { |
19 | public: |
20 | explicit QSemaphore(int n = 0); |
21 | ~QSemaphore(); |
22 | |
23 | void acquire(int n = 1); |
24 | bool tryAcquire(int n = 1); |
25 | QT_CORE_INLINE_SINCE(6, 6) |
26 | bool tryAcquire(int n, int timeout); |
27 | bool tryAcquire(int n, QDeadlineTimer timeout); |
28 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
29 | template <typename Rep, typename Period> |
30 | bool tryAcquire(int n, std::chrono::duration<Rep, Period> timeout) |
31 | { return tryAcquire(n, timeout: QDeadlineTimer(timeout)); } |
32 | #endif |
33 | |
34 | void release(int n = 1); |
35 | |
36 | int available() const; |
37 | |
38 | // std::counting_semaphore compatibility: |
39 | bool try_acquire() noexcept { return tryAcquire(); } |
40 | template <typename Rep, typename Period> |
41 | bool try_acquire_for(const std::chrono::duration<Rep, Period> &timeout) |
42 | { return tryAcquire(1, timeout); } |
43 | template <typename Clock, typename Duration> |
44 | bool try_acquire_until(const std::chrono::time_point<Clock, Duration> &tp) |
45 | { |
46 | return try_acquire_for(tp - Clock::now()); |
47 | } |
48 | private: |
49 | Q_DISABLE_COPY(QSemaphore) |
50 | |
51 | union { |
52 | QSemaphorePrivate *d; |
53 | QBasicAtomicInteger<quintptr> u; |
54 | QBasicAtomicInteger<quint32> u32[2]; |
55 | QBasicAtomicInteger<quint64> u64; |
56 | }; |
57 | }; |
58 | |
59 | #if QT_CORE_INLINE_IMPL_SINCE(6, 6) |
60 | bool QSemaphore::tryAcquire(int n, int timeout) |
61 | { |
62 | return tryAcquire(n, timeout: QDeadlineTimer(timeout)); |
63 | } |
64 | #endif |
65 | |
66 | class QSemaphoreReleaser |
67 | { |
68 | public: |
69 | Q_NODISCARD_CTOR |
70 | QSemaphoreReleaser() = default; |
71 | Q_NODISCARD_CTOR |
72 | explicit QSemaphoreReleaser(QSemaphore &sem, int n = 1) noexcept |
73 | : m_sem(&sem), m_n(n) {} |
74 | Q_NODISCARD_CTOR |
75 | explicit QSemaphoreReleaser(QSemaphore *sem, int n = 1) noexcept |
76 | : m_sem(sem), m_n(n) {} |
77 | Q_NODISCARD_CTOR |
78 | QSemaphoreReleaser(QSemaphoreReleaser &&other) noexcept |
79 | : m_sem(other.cancel()), m_n(other.m_n) {} |
80 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSemaphoreReleaser) |
81 | |
82 | ~QSemaphoreReleaser() |
83 | { |
84 | if (m_sem) |
85 | m_sem->release(n: m_n); |
86 | } |
87 | |
88 | void swap(QSemaphoreReleaser &other) noexcept |
89 | { |
90 | qt_ptr_swap(lhs&: m_sem, rhs&: other.m_sem); |
91 | std::swap(a&: m_n, b&: other.m_n); |
92 | } |
93 | |
94 | QSemaphore *semaphore() const noexcept |
95 | { return m_sem; } |
96 | |
97 | QSemaphore *cancel() noexcept |
98 | { |
99 | return std::exchange(obj&: m_sem, new_val: nullptr); |
100 | } |
101 | |
102 | private: |
103 | QSemaphore *m_sem = nullptr; |
104 | int m_n; |
105 | }; |
106 | |
107 | QT_END_NAMESPACE |
108 | |
109 | #endif // QSEMAPHORE_H |
110 | |