#ifndef STD_THREAD_H_ #define STD_THREAD_H_ #define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) #define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #ifndef __has_include #define __has_include(s) 0 #endif #if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID // GCC 4.4 provides #ifndef _GLIBCXX_USE_SCHED_YIELD #define _GLIBCXX_USE_SCHED_YIELD #endif #include #elif __has_include() && !ANDROID // Clang + libc++ #include #else // partial std::thread implementation for win32/pthread #include #if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) #define USE_RVALUE_REFERENCES #endif #ifdef __APPLE__ #import #endif #if defined(_WIN32) // WIN32 #define WIN32_LEAN_AND_MEAN #include #if defined(_MSC_VER) && defined(_MT) // When linking with LIBCMT (the multithreaded C library), Microsoft recommends // using _beginthreadex instead of CreateThread. #define USE_BEGINTHREADEX #include #endif #ifdef USE_BEGINTHREADEX #define THREAD_ID unsigned #define THREAD_RETURN unsigned __stdcall #else #define THREAD_ID DWORD #define THREAD_RETURN DWORD WINAPI #endif #define THREAD_HANDLE HANDLE #else // PTHREAD #include #ifndef _POSIX_THREADS #error unsupported platform (no pthreads?) #endif #include #define THREAD_ID pthread_t #define THREAD_HANDLE pthread_t #define THREAD_RETURN void* #endif namespace std { class thread { public: typedef THREAD_HANDLE native_handle_type; class id { friend class thread; public: id() : m_thread(0) {} id(THREAD_ID _id) : m_thread(_id) {} bool operator==(const id& rhs) const { return m_thread == rhs.m_thread; } bool operator!=(const id& rhs) const { return !(*this == rhs); } bool operator<(const id& rhs) const { return m_thread < rhs.m_thread; } private: THREAD_ID m_thread; }; // no variadic template support in msvc //template //thread(C&& func, A&&... args); template thread(C func) { StartThread(new Func(func)); } template thread(C func, A arg) { StartThread(new FuncArg(func, arg)); } thread() /*= default;*/ {} #ifdef USE_RVALUE_REFERENCES thread(const thread&) /*= delete*/; thread(thread&& other) { #else thread(const thread& t) { // ugly const_cast to get around lack of rvalue references thread& other = const_cast(t); #endif swap(other); } #ifdef USE_RVALUE_REFERENCES thread& operator=(const thread&) /*= delete*/; thread& operator=(thread&& other) { #else thread& operator=(const thread& t) { // ugly const_cast to get around lack of rvalue references thread& other = const_cast(t); #endif if (joinable()) detach(); swap(other); return *this; } ~thread() { if (joinable()) detach(); } bool joinable() const { return m_id != id(); } id get_id() const { return m_id; } native_handle_type native_handle() { #ifdef _WIN32 return m_handle; #else return m_id.m_thread; #endif } void join() { #ifdef _WIN32 WaitForSingleObject(m_handle, INFINITE); detach(); #else pthread_join(m_id.m_thread, NULL); m_id = id(); #endif } void detach() { #ifdef _WIN32 CloseHandle(m_handle); #else pthread_detach(m_id.m_thread); #endif m_id = id(); } void swap(thread& other) { std::swap(m_id, other.m_id); #ifdef _WIN32 std::swap(m_handle, other.m_handle); #endif } static unsigned hardware_concurrency() { #ifdef _WIN32 SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); return static_cast(sysinfo.dwNumberOfProcessors); #else return 0; #endif } private: id m_id; #ifdef _WIN32 native_handle_type m_handle; #endif template void StartThread(F* param) { #ifdef USE_BEGINTHREADEX m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); #elif defined(_WIN32) m_handle = CreateThread(NULL, 0, &RunAndDelete, param, 0, &m_id.m_thread); #else pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 1024 * 1024); if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete, param)) m_id = id(); #endif } template class Func { public: Func(C _func) : func(_func) {} void Run() { func(); } private: C const func; }; template class FuncArg { public: FuncArg(C _func, A _arg) : func(_func), arg(_arg) {} void Run() { func(arg); } private: C const func; A arg; }; template static THREAD_RETURN RunAndDelete(void* param) { #ifdef __APPLE__ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; #endif static_cast(param)->Run(); delete static_cast(param); #ifdef __APPLE__ [pool release]; #endif return 0; } }; namespace this_thread { inline void yield() { #ifdef _WIN32 SwitchToThread(); #else sleep(0); #endif } inline thread::id get_id() { #ifdef _WIN32 return GetCurrentThreadId(); #else return pthread_self(); #endif } } // namespace this_thread } // namespace std #undef USE_RVALUE_REFERENCES #undef USE_BEGINTHREADEX #undef THREAD_ID #undef THREAD_RETURN #undef THREAD_HANDLE #endif #endif