| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- #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__
- // GCC 4.4 provides <thread>
- #ifndef _GLIBCXX_USE_SCHED_YIELD
- #define _GLIBCXX_USE_SCHED_YIELD
- #endif
- #include <thread>
- #elif __has_include(<thread>) && !ANDROID
- // Clang + libc++
- #include <thread>
- #else
- // partial std::thread implementation for win32/pthread
- #include <algorithm>
- #if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
- #define USE_RVALUE_REFERENCES
- #endif
- #ifdef __APPLE__
- #import <Foundation/NSAutoreleasePool.h>
- #endif
- #if defined(_WIN32)
- // WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <Windows.h>
- #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 <process.h>
- #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 <unistd.h>
- #ifndef _POSIX_THREADS
- #error unsupported platform (no pthreads?)
- #endif
- #include <pthread.h>
- #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 <typename C, typename... A>
- //thread(C&& func, A&&... args);
- template <typename C>
- thread(C func)
- {
- StartThread(new Func<C>(func));
- }
- template <typename C, typename A>
- thread(C func, A arg)
- {
- StartThread(new FuncArg<C, A>(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<thread&>(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<thread&>(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<unsigned>(sysinfo.dwNumberOfProcessors);
- #else
- return 0;
- #endif
- }
- private:
- id m_id;
-
- #ifdef _WIN32
- native_handle_type m_handle;
- #endif
- template <typename F>
- void StartThread(F* param)
- {
- #ifdef USE_BEGINTHREADEX
- m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
- #elif defined(_WIN32)
- m_handle = CreateThread(NULL, 0, &RunAndDelete<F>, 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<F>, param))
- m_id = id();
- #endif
- }
-
- template <typename C>
- class Func
- {
- public:
- Func(C _func) : func(_func) {}
- void Run() { func(); }
- private:
- C const func;
- };
- template <typename C, typename A>
- class FuncArg
- {
- public:
- FuncArg(C _func, A _arg) : func(_func), arg(_arg) {}
- void Run() { func(arg); }
- private:
- C const func;
- A arg;
- };
- template <typename F>
- static THREAD_RETURN RunAndDelete(void* param)
- {
- #ifdef __APPLE__
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- #endif
- static_cast<F*>(param)->Run();
- delete static_cast<F*>(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
|