Support for jthread and stop_token
* include/Makefile.am: Add <stop_token> header. * include/Makefile.in: Regenerate. * include/std/condition_variable: Add overloads for stop_token support to condition_variable_any. * include/std/stop_token: New file. * include/std/thread: Add jthread type. * include/std/version (__cpp_lib_jthread): New value. * testsuite/30_threads/condition_variable_any/stop_token/1.cc: New test. * testsuite/30_threads/condition_variable_any/stop_token/2.cc: New test. * testsuite/30_threads/condition_variable_any/stop_token/wait_on.cc: New test. * testsuite/30_threads/jthread/1.cc: New test. * testsuite/30_threads/jthread/2.cc: New test. * testsuite/30_threads/jthread/jthread.cc: New test. * testsuite/30_threads/stop_token/1.cc: New test. * testsuite/30_threads/stop_token/2.cc: New test. * testsuite/30_threads/stop_token/stop_token.cc: New test. From-SVN: r278274
This commit is contained in:
parent
f8aea5e37d
commit
942c4b32b0
16 changed files with 1197 additions and 0 deletions
|
@ -1,3 +1,22 @@
|
|||
2019-11-14 Thomas Rodgers <trodgers@redhat.com>
|
||||
|
||||
* include/Makefile.am: Add <stop_token> header.
|
||||
* include/Makefile.in: Regenerate.
|
||||
* include/std/condition_variable: Add overloads for stop_token support
|
||||
to condition_variable_any.
|
||||
* include/std/stop_token: New file.
|
||||
* include/std/thread: Add jthread type.
|
||||
* include/std/version (__cpp_lib_jthread): New value.
|
||||
* testsuite/30_threads/condition_variable_any/stop_token/1.cc: New test.
|
||||
* testsuite/30_threads/condition_variable_any/stop_token/2.cc: New test.
|
||||
* testsuite/30_threads/condition_variable_any/stop_token/wait_on.cc: New test.
|
||||
* testsuite/30_threads/jthread/1.cc: New test.
|
||||
* testsuite/30_threads/jthread/2.cc: New test.
|
||||
* testsuite/30_threads/jthread/jthread.cc: New test.
|
||||
* testsuite/30_threads/stop_token/1.cc: New test.
|
||||
* testsuite/30_threads/stop_token/2.cc: New test.
|
||||
* testsuite/30_threads/stop_token/stop_token.cc: New test.
|
||||
|
||||
2019-11-14 Edward Smith-Rowland <3dw4rd@verizon.net>
|
||||
|
||||
Implement the <array> part of C++20 p1032 Misc constexpr bits.
|
||||
|
|
|
@ -74,6 +74,7 @@ std_headers = \
|
|||
${std_srcdir}/sstream \
|
||||
${std_srcdir}/stack \
|
||||
${std_srcdir}/stdexcept \
|
||||
${std_srcdir}/stop_token \
|
||||
${std_srcdir}/streambuf \
|
||||
${std_srcdir}/string \
|
||||
${std_srcdir}/string_view \
|
||||
|
|
|
@ -418,6 +418,7 @@ std_headers = \
|
|||
${std_srcdir}/sstream \
|
||||
${std_srcdir}/stack \
|
||||
${std_srcdir}/stdexcept \
|
||||
${std_srcdir}/stop_token \
|
||||
${std_srcdir}/streambuf \
|
||||
${std_srcdir}/string \
|
||||
${std_srcdir}/string_view \
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#else
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <bits/std_mutex.h>
|
||||
#include <bits/unique_lock.h>
|
||||
#include <ext/concurrence.h>
|
||||
|
@ -45,6 +46,11 @@
|
|||
#include <bits/shared_ptr.h>
|
||||
#include <bits/cxxabi_forced.h>
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
#define __cpp_lib_jthread 201907L
|
||||
#include <stop_token>
|
||||
#endif
|
||||
|
||||
#if defined(_GLIBCXX_HAS_GTHREADS)
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
@ -360,6 +366,84 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
wait_for(_Lock& __lock,
|
||||
const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
|
||||
{ return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
|
||||
|
||||
#ifdef __cpp_lib_jthread
|
||||
template <class _Lock, class _Predicate>
|
||||
bool wait_on(_Lock& __lock,
|
||||
stop_token __stoken,
|
||||
_Predicate __p)
|
||||
{
|
||||
if (__stoken.stop_requested())
|
||||
{
|
||||
return __p();
|
||||
}
|
||||
|
||||
std::stop_callback __cb(__stoken, [this] { notify_all(); });
|
||||
shared_ptr<mutex> __mutex = _M_mutex;
|
||||
while (!__p())
|
||||
{
|
||||
unique_lock<mutex> __my_lock(*__mutex);
|
||||
if (__stoken.stop_requested())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// *__mutex must be unlocked before re-locking __lock so move
|
||||
// ownership of *__mutex lock to an object with shorter lifetime.
|
||||
_Unlock<_Lock> __unlock(__lock);
|
||||
unique_lock<mutex> __my_lock2(std::move(__my_lock));
|
||||
_M_cond.wait(__my_lock2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _Lock, class _Clock, class _Duration, class _Predicate>
|
||||
bool wait_on_until(_Lock& __lock,
|
||||
stop_token __stoken,
|
||||
const chrono::time_point<_Clock, _Duration>& __abs_time,
|
||||
_Predicate __p)
|
||||
{
|
||||
if (__stoken.stop_requested())
|
||||
{
|
||||
return __p();
|
||||
}
|
||||
|
||||
std::stop_callback __cb(__stoken, [this] { notify_all(); });
|
||||
shared_ptr<mutex> __mutex = _M_mutex;
|
||||
while (!__p())
|
||||
{
|
||||
bool __stop;
|
||||
{
|
||||
unique_lock<mutex> __my_lock(*__mutex);
|
||||
if (__stoken.stop_requested())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_Unlock<_Lock> __u(__lock);
|
||||
unique_lock<mutex> __my_lock2(std::move(__my_lock));
|
||||
const auto __status = _M_cond.wait_until(__my_lock2, __abs_time);
|
||||
__stop = (__status == std::cv_status::timeout) || __stoken.stop_requested();
|
||||
}
|
||||
if (__stop)
|
||||
{
|
||||
return __p();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _Lock, class _Rep, class _Period, class _Predicate>
|
||||
bool wait_on_for(_Lock& __lock,
|
||||
stop_token __stoken,
|
||||
const chrono::duration<_Rep, _Period>& __rel_time,
|
||||
_Predicate __p)
|
||||
{
|
||||
auto __abst = std::chrono::steady_clock::now() + __rel_time;
|
||||
return wait_on_until(__lock,
|
||||
std::move(__stoken),
|
||||
__abst,
|
||||
std::move(__p));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // end inline namespace
|
||||
|
|
370
libstdc++-v3/include/std/stop_token
Normal file
370
libstdc++-v3/include/std/stop_token
Normal file
|
@ -0,0 +1,370 @@
|
|||
// <stop_token> -*- C++ -*-
|
||||
|
||||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional
|
||||
// permissions described in the GCC Runtime Library Exception, version
|
||||
// 3.1, as published by the Free Software Foundation.
|
||||
|
||||
// You should have received a copy of the GNU General Public License and
|
||||
// a copy of the GCC Runtime Library Exception along with this program;
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file include/stop_token
|
||||
* This is a Standard C++ Library header.
|
||||
*/
|
||||
|
||||
#ifndef _GLIBCXX_STOP_TOKEN
|
||||
#define _GLIBCXX_STOP_TOKEN
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
#define __cpp_lib_jthread 201907L
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
class stop_source;
|
||||
template<typename _Callback>
|
||||
class stop_callback;
|
||||
|
||||
struct nostopstate_t { explicit nostopstate_t() = default; };
|
||||
inline constexpr nostopstate_t nostopstate();
|
||||
|
||||
class stop_token
|
||||
{
|
||||
public:
|
||||
stop_token() noexcept = default;
|
||||
|
||||
stop_token(const stop_token& __other) noexcept = default;
|
||||
stop_token(stop_token&& __other) noexcept = default;
|
||||
|
||||
~stop_token() = default;
|
||||
|
||||
stop_token&
|
||||
operator=(const stop_token& __rhs) noexcept = default;
|
||||
|
||||
stop_token&
|
||||
operator=(stop_token&& __rhs) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool
|
||||
stop_possible() const noexcept
|
||||
{
|
||||
return static_cast<bool>(_M_state);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool
|
||||
stop_requested() const noexcept
|
||||
{
|
||||
return stop_possible() && _M_state->_M_stop_requested();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend bool
|
||||
operator==(const stop_token& __a, const stop_token& __b)
|
||||
{
|
||||
return __a._M_state == __b._M_state;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend bool
|
||||
operator!=(const stop_token& __a, const stop_token& __b)
|
||||
{
|
||||
return __a._M_state == __b._M_state;
|
||||
}
|
||||
|
||||
private:
|
||||
friend stop_source;
|
||||
template<typename _Callback>
|
||||
friend class stop_callback;
|
||||
|
||||
struct _Stop_cb {
|
||||
void(*_M_callback)(_Stop_cb*);
|
||||
_Stop_cb* _M_prev = nullptr;
|
||||
_Stop_cb* _M_next = nullptr;
|
||||
|
||||
template<typename _Cb>
|
||||
_Stop_cb(_Cb&& __cb)
|
||||
: _M_callback(std::move(__cb))
|
||||
{ }
|
||||
|
||||
bool
|
||||
_M_linked() const
|
||||
{
|
||||
return (_M_prev != nullptr)
|
||||
|| (_M_next != nullptr);
|
||||
}
|
||||
|
||||
static void
|
||||
_S_execute(_Stop_cb* __cb) noexcept
|
||||
{
|
||||
__cb->_M_callback(__cb);
|
||||
__cb->_M_prev = __cb->_M_next = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct _Stop_state_t {
|
||||
std::atomic<bool> _M_stopped;
|
||||
std::mutex _M_mtx;
|
||||
_Stop_cb* _M_head = nullptr;
|
||||
|
||||
_Stop_state_t()
|
||||
: _M_stopped{false}
|
||||
{ }
|
||||
|
||||
bool
|
||||
_M_stop_requested()
|
||||
{
|
||||
return _M_stopped;
|
||||
}
|
||||
|
||||
bool
|
||||
_M_request_stop()
|
||||
{
|
||||
bool __stopped = false;
|
||||
if (_M_stopped.compare_exchange_strong(__stopped, true))
|
||||
{
|
||||
std::unique_lock<std::mutex> __lck{_M_mtx};
|
||||
while (_M_head)
|
||||
{
|
||||
auto __p = _M_head;
|
||||
_M_head = _M_head->_M_next;
|
||||
_Stop_cb::_S_execute(__p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
_M_register_callback(_Stop_cb* __cb)
|
||||
{
|
||||
std::unique_lock<std::mutex> __lck{_M_mtx};
|
||||
if (_M_stopped)
|
||||
return false;
|
||||
|
||||
__cb->_M_next = _M_head;
|
||||
if (_M_head)
|
||||
{
|
||||
_M_head->_M_prev = __cb;
|
||||
}
|
||||
_M_head = __cb;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
_M_remove_callback(_Stop_cb* __cb)
|
||||
{
|
||||
std::unique_lock<std::mutex> __lck{_M_mtx};
|
||||
if (__cb == _M_head)
|
||||
{
|
||||
_M_head = _M_head->_M_next;
|
||||
if (_M_head)
|
||||
{
|
||||
_M_head->_M_prev = nullptr;
|
||||
}
|
||||
}
|
||||
else if (!__cb->_M_linked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
__cb->_M_prev->_M_next = __cb->_M_next;
|
||||
if (__cb->_M_next)
|
||||
{
|
||||
__cb->_M_next->_M_prev = __cb->_M_prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using _Stop_state = std::shared_ptr<_Stop_state_t>;
|
||||
_Stop_state _M_state;
|
||||
|
||||
explicit stop_token(_Stop_state __state)
|
||||
: _M_state{std::move(__state)}
|
||||
{ }
|
||||
};
|
||||
|
||||
class stop_source {
|
||||
using _Stop_state_t = stop_token::_Stop_state_t;
|
||||
using _Stop_state = stop_token::_Stop_state;
|
||||
|
||||
public:
|
||||
stop_source()
|
||||
: _M_state(std::make_shared<_Stop_state_t>())
|
||||
{ }
|
||||
|
||||
explicit stop_source(std::nostopstate_t) noexcept
|
||||
{ }
|
||||
|
||||
stop_source(const stop_source& __other) noexcept
|
||||
: _M_state(__other._M_state)
|
||||
{ }
|
||||
|
||||
stop_source(stop_source&& __other) noexcept
|
||||
: _M_state(std::move(__other._M_state))
|
||||
{ }
|
||||
|
||||
stop_source&
|
||||
operator=(const stop_source& __rhs) noexcept
|
||||
{
|
||||
if (_M_state != __rhs._M_state)
|
||||
_M_state = __rhs._M_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
stop_source&
|
||||
operator=(stop_source&& __rhs) noexcept
|
||||
{
|
||||
std::swap(_M_state, __rhs._M_state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool
|
||||
stop_possible() const noexcept
|
||||
{
|
||||
return static_cast<bool>(_M_state);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool
|
||||
stop_requested() const noexcept
|
||||
{
|
||||
return stop_possible() && _M_state->_M_stop_requested();
|
||||
}
|
||||
|
||||
bool
|
||||
request_stop() const noexcept
|
||||
{
|
||||
if (stop_possible())
|
||||
return _M_state->_M_request_stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
stop_token
|
||||
get_token() const noexcept
|
||||
{
|
||||
return stop_token{_M_state};
|
||||
}
|
||||
|
||||
void
|
||||
swap(stop_source& __other) noexcept
|
||||
{
|
||||
std::swap(_M_state, __other._M_state);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend bool
|
||||
operator==(const stop_source& __a, const stop_source& __b) noexcept
|
||||
{
|
||||
return __a._M_state == __b._M_state;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend bool
|
||||
operator!=(const stop_source& __a, const stop_source& __b) noexcept
|
||||
{
|
||||
return __a._M_state != __b._M_state;
|
||||
}
|
||||
|
||||
private:
|
||||
_Stop_state _M_state;
|
||||
};
|
||||
|
||||
template<typename _Callback>
|
||||
class [[nodiscard]] stop_callback
|
||||
: private stop_token::_Stop_cb
|
||||
{
|
||||
using _Stop_cb = stop_token::_Stop_cb;
|
||||
using _Stop_state = stop_token::_Stop_state;
|
||||
public:
|
||||
using callback_type = _Callback;
|
||||
|
||||
template<typename _Cb,
|
||||
std::enable_if_t<std::is_constructible_v<_Callback, _Cb>, int> = 0>
|
||||
explicit stop_callback(const stop_token& __token, _Cb&& __cb)
|
||||
noexcept(std::is_nothrow_constructible_v<_Callback, _Cb>)
|
||||
: _Stop_cb([](_Stop_cb* __that) noexcept
|
||||
{
|
||||
static_cast<stop_callback*>(__that)->_M_execute();
|
||||
}),
|
||||
_M_cb(std::move(__cb))
|
||||
{
|
||||
auto res = __token._M_state->_M_register_callback(this);
|
||||
if (__token._M_state && res)
|
||||
{
|
||||
_M_state = __token._M_state;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Cb,
|
||||
std::enable_if_t<std::is_constructible_v<_Callback, _Cb>, int> = 0>
|
||||
explicit stop_callback(stop_token&& __token, _Cb&& __cb)
|
||||
noexcept(std::is_nothrow_constructible_v<_Callback, _Cb>)
|
||||
: _Stop_cb([](_Stop_cb* __that) noexcept
|
||||
{
|
||||
static_cast<stop_callback*>(__that)->_M_execute();
|
||||
}),
|
||||
_M_cb(std::move(__cb))
|
||||
{
|
||||
if (__token._M_state && __token._M_state->_M_register_callback(this))
|
||||
{
|
||||
std::swap(_M_state, __token._M_state);
|
||||
}
|
||||
}
|
||||
|
||||
~stop_callback()
|
||||
{
|
||||
if (_M_state)
|
||||
{
|
||||
_M_state->_M_remove_callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
stop_callback(const stop_callback&) = delete;
|
||||
stop_callback& operator=(const stop_callback&) = delete;
|
||||
stop_callback(stop_callback&&) = delete;
|
||||
stop_callback& operator=(stop_callback&&) = delete;
|
||||
|
||||
private:
|
||||
_Callback _M_cb;
|
||||
_Stop_state _M_state = nullptr;
|
||||
|
||||
void
|
||||
_M_execute() noexcept
|
||||
{
|
||||
_M_cb();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Callback>
|
||||
stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
#endif // __cplusplus >= 201703L
|
||||
#endif // _GLIBCXX_STOP_TOKEN
|
|
@ -39,6 +39,13 @@
|
|||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <cerrno>
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
#define __cpp_lib_jthread 201907L
|
||||
#include <functional>
|
||||
#include <stop_token>
|
||||
#endif
|
||||
|
||||
#include <bits/functexcept.h>
|
||||
#include <bits/functional_hash.h>
|
||||
#include <bits/invoke.h>
|
||||
|
@ -409,6 +416,124 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
// @} group threads
|
||||
|
||||
#ifdef __cpp_lib_jthread
|
||||
|
||||
class jthread
|
||||
{
|
||||
public:
|
||||
using id = std::thread::id;
|
||||
using native_handle_type = std::thread::native_handle_type;
|
||||
|
||||
jthread() noexcept
|
||||
: _M_stop_source{ nostopstate_t{ } }
|
||||
{ }
|
||||
|
||||
template<typename _Callable, typename... _Args,
|
||||
typename = std::enable_if_t<!std::is_same_v<std::decay_t<_Callable>, jthread>>>
|
||||
explicit
|
||||
jthread(_Callable&& __f, _Args&&... __args)
|
||||
: _M_thread{[](stop_token __token, auto&& __cb, auto&&... __args)
|
||||
{
|
||||
if constexpr(std::is_invocable_v<_Callable, stop_token, _Args...>)
|
||||
{
|
||||
std::invoke(std::forward<decltype(__cb)>(__cb),
|
||||
std::move(__token),
|
||||
std::forward<decltype(__args)>(__args)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::invoke(std::forward<decltype(__cb)>(__cb),
|
||||
std::forward<decltype(__args)>(__args)...);
|
||||
}
|
||||
},
|
||||
_M_stop_source.get_token(),
|
||||
std::forward<_Callable>(__f),
|
||||
std::forward<_Args>(__args)...}
|
||||
{ }
|
||||
|
||||
jthread(const jthread&) = delete;
|
||||
jthread(jthread&&) noexcept = default;
|
||||
|
||||
~jthread()
|
||||
{
|
||||
if (joinable())
|
||||
{
|
||||
request_stop();
|
||||
join();
|
||||
}
|
||||
}
|
||||
|
||||
jthread&
|
||||
operator=(const jthread&) = delete;
|
||||
|
||||
jthread&
|
||||
operator=(jthread&&) noexcept = default;
|
||||
|
||||
void
|
||||
swap(jthread& __other) noexcept
|
||||
{
|
||||
std::swap(_M_stop_source, __other._M_stop_source);
|
||||
std::swap(_M_thread, __other._M_thread);
|
||||
}
|
||||
|
||||
bool
|
||||
joinable() const noexcept
|
||||
{
|
||||
return _M_thread.joinable();
|
||||
}
|
||||
|
||||
void
|
||||
join()
|
||||
{
|
||||
_M_thread.join();
|
||||
}
|
||||
|
||||
void
|
||||
detach()
|
||||
{
|
||||
_M_thread.detach();
|
||||
}
|
||||
|
||||
id
|
||||
get_id() const noexcept
|
||||
{
|
||||
_M_thread.get_id();
|
||||
}
|
||||
|
||||
native_handle_type
|
||||
native_handle()
|
||||
{
|
||||
return _M_thread.native_handle();
|
||||
}
|
||||
|
||||
static unsigned
|
||||
hardware_concurrency() noexcept
|
||||
{
|
||||
return std::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
[[nodiscard]] stop_source
|
||||
get_stop_source() noexcept
|
||||
{
|
||||
return _M_stop_source;
|
||||
}
|
||||
|
||||
[[nodiscard]] stop_token
|
||||
get_stop_token() const noexcept
|
||||
{
|
||||
return _M_stop_source.get_token();
|
||||
}
|
||||
|
||||
bool request_stop() noexcept
|
||||
{
|
||||
return get_stop_source().request_stop();
|
||||
}
|
||||
|
||||
private:
|
||||
stop_source _M_stop_source;
|
||||
std::thread _M_thread;
|
||||
};
|
||||
#endif // __cpp_lib_jthread
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@
|
|||
#define __cpp_lib_list_remove_return_type 201806L
|
||||
#define __cpp_lib_math_constants 201907L
|
||||
#define __cpp_lib_span 201902L
|
||||
#define __cpp_lib_jthread 201907L
|
||||
#if __cpp_impl_three_way_comparison >= 201907L
|
||||
# define __cpp_lib_three_way_comparison 201711L
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <condition_variable>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <condition_variable>"
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <version>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <version>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <version>"
|
||||
#endif
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a -pthread" }
|
||||
// { dg-do run }
|
||||
// { dg-require-effective-target c++2a }
|
||||
// { dg-require-effective-target pthread }
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using namespace::std::literals;
|
||||
|
||||
void test_wait_on_stop()
|
||||
{
|
||||
bool ready = false;
|
||||
std::mutex mtx;
|
||||
std::condition_variable_any cv;
|
||||
|
||||
std::stop_source src;
|
||||
|
||||
auto tok = src.get_token();
|
||||
std::thread t([&ready, &mtx, &cv, tok]
|
||||
{
|
||||
std::unique_lock lck(mtx);
|
||||
auto res = cv.wait_on(lck, tok, [&ready] { return ready; });
|
||||
if (!res)
|
||||
{
|
||||
VERIFY(tok.stop_requested());
|
||||
}
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(0.5s);
|
||||
VERIFY(!src.stop_requested());
|
||||
src.request_stop();
|
||||
t.join();
|
||||
VERIFY(src.stop_requested());
|
||||
}
|
||||
|
||||
void test_wait_on_until(bool ck = true)
|
||||
{
|
||||
bool ready = false;
|
||||
std::mutex mtx;
|
||||
std::condition_variable_any cv;
|
||||
|
||||
std::stop_source src;
|
||||
|
||||
auto abst = std::chrono::steady_clock::now() + 1.0s;
|
||||
auto tok = src.get_token();
|
||||
std::thread t([ck, &ready, &mtx, &cv, abst, tok]
|
||||
{
|
||||
std::unique_lock lck(mtx);
|
||||
auto res = cv.wait_on_until(lck, tok, abst, [&ready] { return ready; });
|
||||
if (!res && ck)
|
||||
{
|
||||
VERIFY(tok.stop_requested());
|
||||
}
|
||||
});
|
||||
|
||||
if (ck)
|
||||
{
|
||||
std::this_thread::sleep_for(0.5s);
|
||||
VERIFY(!src.stop_requested());
|
||||
src.request_stop();
|
||||
t.join();
|
||||
VERIFY(src.stop_requested());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(1.5s);
|
||||
t.join();
|
||||
VERIFY(!src.stop_requested());
|
||||
}
|
||||
}
|
||||
|
||||
void test_wait_on_for(bool ck = true)
|
||||
{
|
||||
bool ready = false;
|
||||
std::mutex mtx;
|
||||
std::condition_variable_any cv;
|
||||
|
||||
std::stop_source src;
|
||||
|
||||
auto tok = src.get_token();
|
||||
std::thread t([ck, &ready, &mtx, &cv, tok]
|
||||
{
|
||||
std::unique_lock lck(mtx);
|
||||
auto res = cv.wait_on_for(lck, tok, 1.0s, [&ready] { return ready; });
|
||||
if (!res && ck)
|
||||
{
|
||||
VERIFY(tok.stop_requested());
|
||||
}
|
||||
});
|
||||
|
||||
if (ck)
|
||||
{
|
||||
std::this_thread::sleep_for(0.5s);
|
||||
VERIFY(!src.stop_requested());
|
||||
src.request_stop();
|
||||
t.join();
|
||||
VERIFY(src.stop_requested());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(1.5s);
|
||||
t.join();
|
||||
VERIFY(!src.stop_requested());
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_wait_on_stop();
|
||||
test_wait_on_until(false);
|
||||
test_wait_on_until();
|
||||
test_wait_on_for();
|
||||
test_wait_on_for(false);
|
||||
return 0;
|
||||
}
|
27
libstdc++-v3/testsuite/30_threads/jthread/1.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/jthread/1.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <thread>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <thread>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <thread>"
|
||||
#endif
|
27
libstdc++-v3/testsuite/30_threads/jthread/2.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/jthread/2.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <version>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <version>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <version>"
|
||||
#endif
|
198
libstdc++-v3/testsuite/30_threads/jthread/jthread.cc
Normal file
198
libstdc++-v3/testsuite/30_threads/jthread/jthread.cc
Normal file
|
@ -0,0 +1,198 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <atomic>
|
||||
|
||||
using namespace::std::literals;
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
void test_no_stop_token()
|
||||
{
|
||||
// test the basic jthread API (not taking stop_token arg)
|
||||
|
||||
assert(std::jthread::hardware_concurrency() == std::thread::hardware_concurrency());
|
||||
std::stop_token stoken;
|
||||
assert(!stoken.stop_possible());
|
||||
{
|
||||
std::jthread::id t1ID{std::this_thread::get_id()};
|
||||
std::atomic<bool> t1AllSet{false};
|
||||
std::jthread t1([&t1ID, &t1AllSet] {
|
||||
t1ID = std::this_thread::get_id();
|
||||
t1AllSet.store(true);
|
||||
for (int c='9'; c>='0'; --c) {
|
||||
std::this_thread::sleep_for(222ms);
|
||||
}
|
||||
});
|
||||
for (int i=0; !t1AllSet.load(); ++i) {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
assert(t1.joinable());
|
||||
assert(t1ID == t1.get_id());
|
||||
stoken = t1.get_stop_token();
|
||||
assert(!stoken.stop_requested());
|
||||
}
|
||||
assert(stoken.stop_requested());
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
void test_stop_token()
|
||||
{
|
||||
// test the basic thread API (taking stop_token arg)
|
||||
|
||||
std::stop_source ssource;
|
||||
std::stop_source origsource;
|
||||
assert(ssource.stop_possible());
|
||||
assert(!ssource.stop_requested());
|
||||
{
|
||||
std::jthread::id t1ID{std::this_thread::get_id()};
|
||||
std::atomic<bool> t1AllSet{false};
|
||||
std::atomic<bool> t1done{false};
|
||||
std::jthread t1([&t1ID, &t1AllSet, &t1done] (std::stop_token st) {
|
||||
// check some values of the started thread:
|
||||
t1ID = std::this_thread::get_id();
|
||||
t1AllSet.store(true);
|
||||
for (int i=0; !st.stop_requested(); ++i) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
t1done.store(true);
|
||||
},
|
||||
ssource.get_token());
|
||||
for (int i=0; !t1AllSet.load(); ++i) {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
// and check all values:
|
||||
assert(t1.joinable());
|
||||
assert(t1ID == t1.get_id());
|
||||
|
||||
std::this_thread::sleep_for(470ms);
|
||||
origsource = std::move(ssource);
|
||||
ssource = t1.get_stop_source();
|
||||
assert(!ssource.stop_requested());
|
||||
auto ret = ssource.request_stop();
|
||||
assert(ret);
|
||||
ret = ssource.request_stop();
|
||||
assert(!ret);
|
||||
assert(ssource.stop_requested());
|
||||
assert(!t1done.load());
|
||||
assert(!origsource.stop_requested());
|
||||
|
||||
std::this_thread::sleep_for(470ms);
|
||||
origsource.request_stop();
|
||||
}
|
||||
assert(origsource.stop_requested());
|
||||
assert(ssource.stop_requested());
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
void test_join()
|
||||
{
|
||||
std::stop_source ssource;
|
||||
assert(ssource.stop_possible());
|
||||
{
|
||||
std::jthread t1([](std::stop_token stoken) {
|
||||
for (int i=0; !stoken.stop_requested(); ++i) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
});
|
||||
ssource = t1.get_stop_source();
|
||||
std::jthread t2([ssource] () mutable {
|
||||
for (int i=0; i < 10; ++i) {
|
||||
std::this_thread::sleep_for(70ms);
|
||||
}
|
||||
ssource.request_stop();
|
||||
});
|
||||
// wait for all thread to finish:
|
||||
t2.join();
|
||||
assert(!t2.joinable());
|
||||
assert(t1.joinable());
|
||||
t1.join();
|
||||
assert(!t1.joinable());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
void test_detach()
|
||||
{
|
||||
std::stop_source ssource;
|
||||
assert(ssource.stop_possible());
|
||||
std::atomic<bool> t1FinallyInterrupted{false};
|
||||
{
|
||||
std::jthread t0;
|
||||
std::jthread::id t1ID{std::this_thread::get_id()};
|
||||
bool t1IsInterrupted;
|
||||
std::stop_token t1InterruptToken;
|
||||
std::atomic<bool> t1AllSet{false};
|
||||
std::jthread t1([&t1ID, &t1IsInterrupted, &t1InterruptToken, &t1AllSet, &t1FinallyInterrupted]
|
||||
(std::stop_token stoken) {
|
||||
// check some values of the started thread:
|
||||
t1ID = std::this_thread::get_id();
|
||||
t1InterruptToken = stoken;
|
||||
t1IsInterrupted = stoken.stop_requested();
|
||||
assert(stoken.stop_possible());
|
||||
assert(!stoken.stop_requested());
|
||||
t1AllSet.store(true);
|
||||
for (int i=0; !stoken.stop_requested(); ++i) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
t1FinallyInterrupted.store(true);
|
||||
});
|
||||
for (int i=0; !t1AllSet.load(); ++i) {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
assert(!t0.joinable());
|
||||
assert(t1.joinable());
|
||||
assert(t1ID == t1.get_id());
|
||||
assert(t1IsInterrupted == false);
|
||||
assert(t1InterruptToken == t1.get_stop_source().get_token());
|
||||
ssource = t1.get_stop_source();
|
||||
assert(t1InterruptToken.stop_possible());
|
||||
assert(!t1InterruptToken.stop_requested());
|
||||
t1.detach();
|
||||
assert(!t1.joinable());
|
||||
}
|
||||
|
||||
assert(!t1FinallyInterrupted.load());
|
||||
ssource.request_stop();
|
||||
assert(ssource.stop_requested());
|
||||
for (int i=0; !t1FinallyInterrupted.load() && i < 100; ++i) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
assert(t1FinallyInterrupted.load());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::set_terminate([](){
|
||||
assert(false);
|
||||
});
|
||||
|
||||
test_no_stop_token();
|
||||
test_stop_token();
|
||||
test_join();
|
||||
test_detach();
|
||||
}
|
||||
|
27
libstdc++-v3/testsuite/30_threads/stop_token/1.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/stop_token/1.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <stop_token>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <stop_token>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <stop_token>"
|
||||
#endif
|
27
libstdc++-v3/testsuite/30_threads/stop_token/2.cc
Normal file
27
libstdc++-v3/testsuite/30_threads/stop_token/2.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <version>
|
||||
|
||||
#ifndef __cpp_lib_jthread
|
||||
# error "Feature-test macro for jthread missing in <version>"
|
||||
#elif __cpp_lib_jthread != 201907L
|
||||
# error "Feature-test macro for jthread has wrong value in <version>"
|
||||
#endif
|
100
libstdc++-v3/testsuite/30_threads/stop_token/stop_token.cc
Normal file
100
libstdc++-v3/testsuite/30_threads/stop_token/stop_token.cc
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a -pthread" }
|
||||
// { dg-do run }
|
||||
// { dg-require-effective-target c++2a }
|
||||
// { dg-require-effective-target pthread }
|
||||
|
||||
#include <stop_token>
|
||||
#include <iostream>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// create stop_source
|
||||
std::stop_source ssrc;
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(!ssrc.stop_requested());
|
||||
|
||||
// create stop_token from stop_source
|
||||
std::stop_token stok{ssrc.get_token()};
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(!ssrc.stop_requested());
|
||||
VERIFY(stok.stop_possible());
|
||||
VERIFY(!stok.stop_requested());
|
||||
|
||||
// register callback
|
||||
bool cb1called{false};
|
||||
auto cb1 = [&]{
|
||||
std::cout << "cb1" << std::endl;
|
||||
cb1called = true;
|
||||
};
|
||||
{
|
||||
std::stop_callback scb1{stok, cb1};
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(!ssrc.stop_requested());
|
||||
VERIFY(stok.stop_possible());
|
||||
VERIFY(!stok.stop_requested());
|
||||
VERIFY(!cb1called);
|
||||
} // unregister callback
|
||||
|
||||
// register another callback
|
||||
bool cb2called{false};
|
||||
auto cb2 = [&]{
|
||||
VERIFY(stok.stop_requested());
|
||||
cb2called = true;
|
||||
};
|
||||
std::stop_callback scb2a{stok, cb2}; // copies cb2
|
||||
// std::stop_callback scb2b{stok, std::move(cb2)};
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(!ssrc.stop_requested());
|
||||
VERIFY(stok.stop_possible());
|
||||
VERIFY(!stok.stop_requested());
|
||||
VERIFY(!cb1called);
|
||||
VERIFY(!cb2called);
|
||||
|
||||
// request stop
|
||||
auto b = ssrc.request_stop();
|
||||
VERIFY(b);
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(ssrc.stop_requested());
|
||||
VERIFY(stok.stop_possible());
|
||||
VERIFY(stok.stop_requested());
|
||||
VERIFY(!cb1called);
|
||||
VERIFY(cb2called);
|
||||
|
||||
b = ssrc.request_stop();
|
||||
VERIFY(!b);
|
||||
|
||||
// TODO verify the standard requires this
|
||||
#if 0
|
||||
// register another callback
|
||||
bool cb3called{false};
|
||||
std::stop_callback scb3{stok, [&]
|
||||
{
|
||||
cb3called = true;
|
||||
}};
|
||||
VERIFY(ssrc.stop_possible());
|
||||
VERIFY(ssrc.stop_requested());
|
||||
VERIFY(stok.stop_possible());
|
||||
VERIFY(stok.stop_requested());
|
||||
VERIFY(!cb1called);
|
||||
VERIFY(cb2called);
|
||||
VERIFY(cb3called);
|
||||
#endif
|
||||
}
|
Loading…
Add table
Reference in a new issue