0,0 → 1,319 |
// <thread> -*- C++ -*- |
|
// Copyright (C) 2008-2015 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/thread |
* This is a Standard C++ Library header. |
*/ |
|
#ifndef _GLIBCXX_THREAD |
#define _GLIBCXX_THREAD 1 |
|
#pragma GCC system_header |
|
#if __cplusplus < 201103L |
# include <bits/c++0x_warning.h> |
#else |
|
#include <chrono> |
#include <functional> |
#include <memory> |
#include <bits/functexcept.h> |
#include <bits/functional_hash.h> |
#include <bits/gthr.h> |
|
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) |
|
namespace std _GLIBCXX_VISIBILITY(default) |
{ |
_GLIBCXX_BEGIN_NAMESPACE_VERSION |
|
/** |
* @defgroup threads Threads |
* @ingroup concurrency |
* |
* Classes for thread support. |
* @{ |
*/ |
|
/// thread |
class thread |
{ |
public: |
typedef __gthread_t native_handle_type; |
struct _Impl_base; |
typedef shared_ptr<_Impl_base> __shared_base_type; |
|
/// thread::id |
class id |
{ |
native_handle_type _M_thread; |
|
public: |
id() noexcept : _M_thread() { } |
|
explicit |
id(native_handle_type __id) : _M_thread(__id) { } |
|
private: |
friend class thread; |
friend class hash<thread::id>; |
|
friend bool |
operator==(thread::id __x, thread::id __y) noexcept |
{ return __gthread_equal(__x._M_thread, __y._M_thread); } |
|
friend bool |
operator<(thread::id __x, thread::id __y) noexcept |
{ return __x._M_thread < __y._M_thread; } |
|
template<class _CharT, class _Traits> |
friend basic_ostream<_CharT, _Traits>& |
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id); |
}; |
|
// Simple base type that the templatized, derived class containing |
// an arbitrary functor can be converted to and called. |
struct _Impl_base |
{ |
__shared_base_type _M_this_ptr; |
|
inline virtual ~_Impl_base(); |
|
virtual void _M_run() = 0; |
}; |
|
template<typename _Callable> |
struct _Impl : public _Impl_base |
{ |
_Callable _M_func; |
|
_Impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f)) |
{ } |
|
void |
_M_run() { _M_func(); } |
}; |
|
private: |
id _M_id; |
|
public: |
thread() noexcept = default; |
// _GLIBCXX_RESOLVE_LIB_DEFECTS |
// 2097. packaged_task constructors should be constrained |
thread(thread&) = delete; |
thread(const thread&) = delete; |
|
thread(thread&& __t) noexcept |
{ swap(__t); } |
|
template<typename _Callable, typename... _Args> |
explicit |
thread(_Callable&& __f, _Args&&... __args) |
{ |
#ifdef GTHR_ACTIVE_PROXY |
// Create a reference to pthread_create, not just the gthr weak symbol |
_M_start_thread(_M_make_routine(std::__bind_simple( |
std::forward<_Callable>(__f), |
std::forward<_Args>(__args)...)), |
reinterpret_cast<void(*)()>(&pthread_create)); |
#else |
_M_start_thread(_M_make_routine(std::__bind_simple( |
std::forward<_Callable>(__f), |
std::forward<_Args>(__args)...))); |
#endif |
} |
|
~thread() |
{ |
if (joinable()) |
std::terminate(); |
} |
|
thread& operator=(const thread&) = delete; |
|
thread& operator=(thread&& __t) noexcept |
{ |
if (joinable()) |
std::terminate(); |
swap(__t); |
return *this; |
} |
|
void |
swap(thread& __t) noexcept |
{ std::swap(_M_id, __t._M_id); } |
|
bool |
joinable() const noexcept |
{ return !(_M_id == id()); } |
|
void |
join(); |
|
void |
detach(); |
|
thread::id |
get_id() const noexcept |
{ return _M_id; } |
|
/** @pre thread is joinable |
*/ |
native_handle_type |
native_handle() |
{ return _M_id._M_thread; } |
|
// Returns a value that hints at the number of hardware thread contexts. |
static unsigned int |
hardware_concurrency() noexcept; |
|
private: |
void |
_M_start_thread(__shared_base_type, void (*)()); |
|
void |
_M_start_thread(__shared_base_type); |
|
template<typename _Callable> |
shared_ptr<_Impl<_Callable>> |
_M_make_routine(_Callable&& __f) |
{ |
// Create and allocate full data structure, not base. |
return std::make_shared<_Impl<_Callable>>(std::forward<_Callable>(__f)); |
} |
}; |
|
inline thread::_Impl_base::~_Impl_base() = default; |
|
inline void |
swap(thread& __x, thread& __y) noexcept |
{ __x.swap(__y); } |
|
inline bool |
operator!=(thread::id __x, thread::id __y) noexcept |
{ return !(__x == __y); } |
|
inline bool |
operator<=(thread::id __x, thread::id __y) noexcept |
{ return !(__y < __x); } |
|
inline bool |
operator>(thread::id __x, thread::id __y) noexcept |
{ return __y < __x; } |
|
inline bool |
operator>=(thread::id __x, thread::id __y) noexcept |
{ return !(__x < __y); } |
|
// DR 889. |
/// std::hash specialization for thread::id. |
template<> |
struct hash<thread::id> |
: public __hash_base<size_t, thread::id> |
{ |
size_t |
operator()(const thread::id& __id) const noexcept |
{ return std::_Hash_impl::hash(__id._M_thread); } |
}; |
|
template<class _CharT, class _Traits> |
inline basic_ostream<_CharT, _Traits>& |
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) |
{ |
if (__id == thread::id()) |
return __out << "thread::id of a non-executing thread"; |
else |
return __out << __id._M_thread; |
} |
|
_GLIBCXX_END_NAMESPACE_VERSION |
|
/** @namespace std::this_thread |
* @brief ISO C++ 2011 entities sub-namespace for thread. |
* 30.3.2 Namespace this_thread. |
*/ |
namespace this_thread |
{ |
_GLIBCXX_BEGIN_NAMESPACE_VERSION |
|
/// get_id |
inline thread::id |
get_id() noexcept { return thread::id(__gthread_self()); } |
|
/// yield |
inline void |
yield() noexcept |
{ |
#ifdef _GLIBCXX_USE_SCHED_YIELD |
__gthread_yield(); |
#endif |
} |
|
void |
__sleep_for(chrono::seconds, chrono::nanoseconds); |
|
/// sleep_for |
template<typename _Rep, typename _Period> |
inline void |
sleep_for(const chrono::duration<_Rep, _Period>& __rtime) |
{ |
if (__rtime <= __rtime.zero()) |
return; |
auto __s = chrono::duration_cast<chrono::seconds>(__rtime); |
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s); |
#ifdef _GLIBCXX_USE_NANOSLEEP |
__gthread_time_t __ts = |
{ |
static_cast<std::time_t>(__s.count()), |
static_cast<long>(__ns.count()) |
}; |
::nanosleep(&__ts, 0); |
#else |
__sleep_for(__s, __ns); |
#endif |
} |
|
/// sleep_until |
template<typename _Clock, typename _Duration> |
inline void |
sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) |
{ |
auto __now = _Clock::now(); |
if (__now < __atime) |
sleep_for(__atime - __now); |
} |
|
_GLIBCXX_END_NAMESPACE_VERSION |
} |
|
// @} group threads |
|
} // namespace |
|
#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 |
|
#endif // C++11 |
|
#endif // _GLIBCXX_THREAD |