cxx/include/thread
2010-08-10 20:48:29 +00:00

327 lines
6.9 KiB
C++

// -*- C++ -*-
//===--------------------------- thread -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_THREAD
#define _LIBCPP_THREAD
/*
thread synopsis
#define __STDCPP_THREADS __cplusplus
namespace std
{
class thread
{
public:
class id;
typedef pthread_t native_handle_type;
thread();
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
~thread();
thread(const thread&) = delete;
thread(thread&& t);
thread& operator=(const thread&) = delete;
thread& operator=(thread&& t);
void swap(thread& t);
bool joinable() const;
void join();
void detach();
id get_id() const;
native_handle_type native_handle();
static unsigned hardware_concurrency();
};
void swap(thread& x, thread& y);
class thread::id
{
public:
id();
};
bool operator==(thread::id x, thread::id y);
bool operator!=(thread::id x, thread::id y);
bool operator< (thread::id x, thread::id y);
bool operator<=(thread::id x, thread::id y);
bool operator> (thread::id x, thread::id y);
bool operator>=(thread::id x, thread::id y);
template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& out, thread::id id);
namespace this_thread
{
thread::id get_id();
void yield();
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
} // this_thread
} // std
*/
#include <__config>
#include <iosfwd>
#include <__functional_base>
#include <type_traits>
#include <cstddef>
#include <functional>
#include <memory>
#include <system_error>
#include <chrono>
#include <__mutex_base>
#include <pthread.h>
#pragma GCC system_header
#define __STDCPP_THREADS __cplusplus
_LIBCPP_BEGIN_NAMESPACE_STD
class thread;
class __thread_id;
namespace this_thread
{
__thread_id get_id();
} // this_thread
class __thread_id
{
// FIXME: pthread_t is a pointer on Darwin but a long on Linux.
// NULL is the no-thread value on Darwin. Someone needs to check
// on other platforms. We assume 0 works everywhere for now.
pthread_t __id_;
public:
__thread_id() : __id_(0) {}
friend bool operator==(__thread_id __x, __thread_id __y)
{return __x.__id_ == __y.__id_;}
friend bool operator!=(__thread_id __x, __thread_id __y)
{return !(__x == __y);}
friend bool operator< (__thread_id __x, __thread_id __y)
{return __x.__id_ < __y.__id_;}
friend bool operator<=(__thread_id __x, __thread_id __y)
{return !(__y < __x);}
friend bool operator> (__thread_id __x, __thread_id __y)
{return __y < __x ;}
friend bool operator>=(__thread_id __x, __thread_id __y)
{return !(__x < __y);}
template<class _CharT, class _Traits>
friend
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
{return __os << __id.__id_;}
private:
__thread_id(pthread_t __id) : __id_(__id) {}
friend __thread_id this_thread::get_id();
friend class thread;
};
template<class _Tp> struct hash;
template<>
struct hash<__thread_id>
: public unary_function<__thread_id, size_t>
{
size_t operator()(__thread_id __v) const
{
const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
return *__p;
}
};
namespace this_thread
{
inline
__thread_id
get_id()
{
return pthread_self();
}
} // this_thread
class thread
{
pthread_t __t_;
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
thread(const thread&) = delete;
thread& operator=(const thread&) = delete;
#else
thread(const thread&);
thread& operator=(const thread&);
#endif
public:
typedef __thread_id id;
typedef pthread_t native_handle_type;
thread() : __t_(0) {}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _F, class ..._Args,
class = typename enable_if
<
!is_same<typename decay<_F>::type, thread>::value
>::type
>
explicit thread(_F&& __f, _Args&&... __args);
#else
template <class _F> explicit thread(_F __f);
#endif
~thread();
#ifdef _LIBCPP_MOVE
thread(thread&& __t) : __t_(__t.__t_) {__t.__t_ = 0;}
thread& operator=(thread&& __t);
#endif
void swap(thread& __t) {_STD::swap(__t_, __t.__t_);}
bool joinable() const {return __t_ != 0;}
void join();
void detach();
id get_id() const {return __t_;}
native_handle_type native_handle() {return __t_;}
static unsigned hardware_concurrency();
};
template <class _F>
void*
__thread_proxy(void* __vp)
{
std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
(*__p)();
return nullptr;
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _F, class ..._Args,
class
>
thread::thread(_F&& __f, _Args&&... __args)
{
typedef decltype(bind(std::forward<_F>(__f), std::forward<_Args>(__args)...)) _G;
std::unique_ptr<_G> __p(new _G(bind(std::forward<_F>(__f),
std::forward<_Args>(__args)...)));
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_G>, __p.get());
if (__ec == 0)
__p.release();
else
__throw_system_error(__ec, "thread constructor failed");
}
#else
template <class _F>
thread::thread(_F __f)
{
std::unique_ptr<_F> __p(new _F(__f));
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_F>, __p.get());
if (__ec == 0)
__p.release();
else
__throw_system_error(__ec, "thread constructor failed");
}
#endif
#ifdef _LIBCPP_MOVE
inline
thread&
thread::operator=(thread&& __t)
{
if (__t_ != 0)
terminate();
__t_ = __t.__t_;
__t.__t_ = 0;
return *this;
}
#endif
inline
void swap(thread& __x, thread& __y) {__x.swap(__y);}
namespace this_thread
{
void sleep_for(const chrono::nanoseconds& ns);
template <class _Rep, class _Period>
void
sleep_for(const chrono::duration<_Rep, _Period>& __d)
{
using namespace chrono;
nanoseconds __ns = duration_cast<nanoseconds>(__d);
if (__ns < __d)
++__ns;
sleep_for(__ns);
}
template <class _Clock, class _Duration>
void
sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
{
using namespace chrono;
mutex __mut;
condition_variable __cv;
unique_lock<mutex> __lk(__mut);
while (_Clock::now() < __t)
__cv.wait_until(__lk, __t);
}
template <class _Duration>
inline
void
sleep_until(const chrono::time_point<chrono::monotonic_clock, _Duration>& __t)
{
using namespace chrono;
sleep_for(__t - monotonic_clock::now());
}
inline
void yield() {sched_yield();}
} // this_thread
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_THREAD