240 lines
5.7 KiB
Plaintext
240 lines
5.7 KiB
Plaintext
#pragma once
|
|
|
|
#if __cplusplus < 201103L
|
|
#error "C++ version lower than C++11"
|
|
#endif
|
|
|
|
//#if defined(RT_USING_PTHREADS)
|
|
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sched.h>
|
|
#include <rtthread.h>
|
|
|
|
#include <cstddef>
|
|
#include <cerrno>
|
|
#include <ostream>
|
|
#include <functional>
|
|
#include <utility>
|
|
#include <chrono>
|
|
#include <memory>
|
|
|
|
#define rt_cpp_thread_t pthread_t
|
|
#ifndef PTHREAD_NUM_MAX
|
|
#define PTHREAD_NUM_MAX 32
|
|
#endif
|
|
#define CPP_UNJOINABLE_THREAD PTHREAD_NUM_MAX
|
|
|
|
namespace std
|
|
{
|
|
#define __STDCPP_THREADS__ __cplusplus
|
|
|
|
|
|
|
|
class thread
|
|
{
|
|
public:
|
|
typedef rt_cpp_thread_t native_handle_type;
|
|
|
|
struct invoker_base;
|
|
typedef shared_ptr<invoker_base> invoker_base_ptr;
|
|
|
|
class id
|
|
{
|
|
// basically a wrapper around native_handle_type
|
|
native_handle_type __cpp_thread_t;
|
|
|
|
public:
|
|
id() noexcept : __cpp_thread_t(CPP_UNJOINABLE_THREAD) {}
|
|
|
|
explicit id(native_handle_type hid)
|
|
: __cpp_thread_t(hid) {}
|
|
private:
|
|
friend class thread;
|
|
friend class hash<thread::id>;
|
|
|
|
friend bool operator==(thread::id x, thread::id y) noexcept;
|
|
|
|
friend bool operator<(thread::id x, thread::id y) noexcept;
|
|
|
|
template <class charT, class traits>
|
|
friend basic_ostream<charT, traits>&
|
|
operator<<(basic_ostream<charT, traits>& out, thread::id id);
|
|
};
|
|
|
|
thread() noexcept = default;
|
|
thread(const thread&) = delete;
|
|
thread& operator=(const thread&) = delete;
|
|
~thread();
|
|
|
|
template <class F, class ...Args>
|
|
explicit thread(F&& f, Args&&... args)
|
|
{
|
|
start_thread(make_invoker_ptr(std::bind(
|
|
std::forward<F>(f),
|
|
std::forward<Args>(args)...
|
|
)));
|
|
}
|
|
|
|
thread(thread&& t) noexcept
|
|
{
|
|
swap(t);
|
|
}
|
|
|
|
thread& operator=(thread&& t) noexcept
|
|
{
|
|
if (joinable())
|
|
terminate();
|
|
swap(t);
|
|
return *this;
|
|
}
|
|
|
|
// member functions
|
|
void swap(thread& t) noexcept
|
|
{
|
|
std::swap(_m_thr, t._m_thr);
|
|
}
|
|
|
|
bool joinable() const noexcept
|
|
{
|
|
return (_m_thr.__cpp_thread_t < PTHREAD_NUM_MAX);
|
|
}
|
|
|
|
void join();
|
|
|
|
void detach();
|
|
|
|
id get_id() const noexcept { return _m_thr; }
|
|
|
|
native_handle_type native_handle() { return _m_thr.__cpp_thread_t; }
|
|
|
|
// static members
|
|
static unsigned hardware_concurrency() noexcept;
|
|
|
|
private:
|
|
id _m_thr;
|
|
|
|
void start_thread(invoker_base_ptr b);
|
|
public:
|
|
struct invoker_base
|
|
{
|
|
invoker_base_ptr this_ptr;
|
|
|
|
virtual ~invoker_base() = default;
|
|
|
|
virtual void invoke() = 0;
|
|
};
|
|
|
|
|
|
template<typename Callable>
|
|
struct invoker : public invoker_base
|
|
{
|
|
Callable func;
|
|
|
|
invoker(Callable&& F) : func(std::forward<Callable>(F)) { }
|
|
|
|
void invoke() { func(); }
|
|
};
|
|
|
|
template <typename Callable>
|
|
shared_ptr<invoker<Callable>> make_invoker_ptr(Callable&& F)
|
|
{
|
|
return std::make_shared<invoker<Callable>>(std::forward<Callable>(F));
|
|
}
|
|
|
|
|
|
};
|
|
|
|
inline void swap(thread& x, thread& y) noexcept
|
|
{
|
|
x.swap(y);
|
|
}
|
|
|
|
|
|
inline bool operator==(thread::id x, thread::id y) noexcept
|
|
{
|
|
// From POSIX for pthread_equal:
|
|
//"If either t1 or t2 are not valid thread IDs, the behavior is undefined."
|
|
return x.__cpp_thread_t == y.__cpp_thread_t;
|
|
}
|
|
|
|
inline bool operator!=(thread::id x, thread::id y) noexcept
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
inline bool operator<(thread::id x, thread::id y) noexcept
|
|
{
|
|
return x.__cpp_thread_t < y.__cpp_thread_t;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
inline bool operator>=(thread::id x, thread::id y) noexcept
|
|
{
|
|
return !(x < y);
|
|
}
|
|
|
|
template <class charT, class traits>
|
|
inline basic_ostream<charT, traits>&
|
|
operator<<(basic_ostream<charT, traits>& out, thread::id id)
|
|
{
|
|
if (id == thread::id()) // id is invalid, representing no pthread
|
|
out << "thread::id of a non-executing thread";
|
|
else
|
|
out << id.__cpp_thread_t;
|
|
return out;
|
|
}
|
|
|
|
template <>
|
|
struct hash<thread::id>
|
|
{
|
|
typedef size_t result_type;
|
|
typedef thread::id argument_type;
|
|
size_t operator()(const thread::id& id) const noexcept
|
|
{
|
|
return hash<rt_cpp_thread_t>()(id.__cpp_thread_t);
|
|
}
|
|
};
|
|
|
|
namespace this_thread
|
|
{
|
|
inline thread::id get_id() noexcept
|
|
{
|
|
return thread::id(pthread_self());
|
|
}
|
|
|
|
inline void yield() noexcept
|
|
{
|
|
sched_yield();
|
|
}
|
|
|
|
template <class Rep, class Period>
|
|
inline void sleep_for(const chrono::duration<Rep, Period>& rel_time)
|
|
{
|
|
if (rel_time <= rel_time.zero()) // less than zero, no need to sleep
|
|
return;
|
|
auto milli_secs = chrono::duration_cast<chrono::milliseconds>(rel_time);
|
|
// the precision is limited by rt-thread thread API
|
|
rt_thread_mdelay(milli_secs.count());
|
|
}
|
|
|
|
template <class Clock, class Duration>
|
|
inline void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)
|
|
{
|
|
auto now = Clock::now();
|
|
if (abs_time > now)
|
|
sleep_for(abs_time - now);
|
|
}
|
|
|
|
}
|
|
}
|