diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index dfc179486c8..23fded1cc0f 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -485,6 +485,46 @@ bool QSemaphore::tryAcquire(int n, int timeout) return true; } +/*! + \fn template QSemaphore::tryAcquire(int n, std::chrono::duration timeout) + \overload + \since 6.3 +*/ + +/*! + \fn QSemaphore::try_acquire() + \since 6.3 + + This function is provided for \c{std::counting_semaphore} compatibility. + + It is equivalent to calling \c{tryAcquire(1)}. + + \sa tryAcquire(), try_acquire_for(), try_acquire_until() +*/ + +/*! + \fn template QSemaphore::try_acquire_for(std::chrono::duration timeout) + \since 6.3 + + This function is provided for \c{std::counting_semaphore} compatibility. + + It is equivalent to calling \c{tryAcquire(1, timeout)}. + + \sa tryAcquire(), try_acquire(), try_acquire_until() +*/ + +/*! + \fn template QSemaphore::try_acquire_until(std::chrono::time_point timeout) + \since 6.3 + + This function is provided for \c{std::counting_semaphore} compatibility. + + It is equivalent to calling \c{tryAcquire(1, timeout - Clock::now())}, + which means that adjustments to \c{Clock} are ignored while waiting. + + \sa tryAcquire(), try_acquire(), try_acquire_for() +*/ + /*! \class QSemaphoreReleaser \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call. diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h index d31c9bd6768..b57a2741040 100644 --- a/src/corelib/thread/qsemaphore.h +++ b/src/corelib/thread/qsemaphore.h @@ -41,6 +41,9 @@ #define QSEMAPHORE_H #include +#include // for convertToMilliseconds() + +#include QT_REQUIRE_CONFIG(thread); @@ -57,11 +60,24 @@ public: void acquire(int n = 1); bool tryAcquire(int n = 1); bool tryAcquire(int n, int timeout); + template + bool tryAcquire(int n, std::chrono::duration timeout) + { return tryAcquire(n, QtPrivate::convertToMilliseconds(timeout)); } void release(int n = 1); int available() const; + // std::counting_semaphore compatibility: + bool try_acquire() noexcept { return tryAcquire(); } + template + bool try_acquire_for(const std::chrono::duration &timeout) + { return tryAcquire(1, timeout); } + template + bool try_acquire_until(const std::chrono::time_point &tp) + { + return try_acquire_for(tp - Clock::now()); + } private: Q_DISABLE_COPY(QSemaphore) diff --git a/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp index 9f1512bc44e..1d3f3d67765 100644 --- a/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp +++ b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp @@ -32,6 +32,10 @@ #include #include +#include + +using namespace std::chrono_literals; + class tst_QSemaphore : public QObject { Q_OBJECT @@ -47,6 +51,7 @@ private slots: void tryAcquireWithTimeoutForever(); void producerConsumer(); void raii(); + void stdCompat(); }; static QSemaphore *semaphore = nullptr; @@ -500,7 +505,7 @@ public: void run() override; }; -static const int Timeout = 60 * 1000; // 1min +static const auto Timeout = 1min; void Producer::run() { @@ -599,5 +604,34 @@ void tst_QSemaphore::raii() QCOMPARE(sem.available(), 49); } +void tst_QSemaphore::stdCompat() +{ + QSemaphore sem(1); + + auto now = [] { return std::chrono::steady_clock::now(); }; + + QVERIFY(sem.try_acquire()); + QCOMPARE(sem.available(), 0); + QVERIFY(!sem.try_acquire_for(10ms)); + QCOMPARE(sem.available(), 0); + QVERIFY(!sem.try_acquire_until(now() + 10ms)); + QCOMPARE(sem.available(), 0); + + sem.release(2); + + QVERIFY(sem.try_acquire()); + QVERIFY(sem.try_acquire_for(5ms)); + QCOMPARE(sem.available(), 0); + QVERIFY(!sem.try_acquire_until(now() + 5ms)); + QCOMPARE(sem.available(), 0); + + sem.release(3); + + QVERIFY(sem.try_acquire()); + QVERIFY(sem.try_acquire_for(5s)); + QVERIFY(sem.try_acquire_until(now() + 5s)); + QCOMPARE(sem.available(), 0); +} + QTEST_MAIN(tst_QSemaphore) #include "tst_qsemaphore.moc"