aboutsummaryrefslogtreecommitdiffstats
path: root/include/mingw.thread.h
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2017-01-10 21:26:13 -0500
committerClyne Sullivan <tullivan99@gmail.com>2017-01-10 21:26:13 -0500
commitf800dbc034e7a70a613bab8cd9d147be4f6e88b6 (patch)
treec8714ddc8f6712f07d921c08fd92ae8ef228494b /include/mingw.thread.h
parentc6651145a4a6e6611b585c1a87c127f38751db4b (diff)
windows build
Diffstat (limited to 'include/mingw.thread.h')
-rw-r--r--include/mingw.thread.h167
1 files changed, 167 insertions, 0 deletions
diff --git a/include/mingw.thread.h b/include/mingw.thread.h
new file mode 100644
index 0000000..6c1a997
--- /dev/null
+++ b/include/mingw.thread.h
@@ -0,0 +1,167 @@
+/**
+* @file mingw.thread.h
+* @brief std::thread implementation for MinGW
+* (c) 2013-2016 by Mega Limited, Auckland, New Zealand
+* @author Alexander Vassilev
+*
+* @copyright Simplified (2-clause) BSD License.
+* You should have received a copy of the license along with this
+* program.
+*
+* This code 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.
+* @note
+* This file may become part of the mingw-w64 runtime package. If/when this happens,
+* the appropriate license will be added, i.e. this code will become dual-licensed,
+* and the current BSD 2-clause license will stay.
+*/
+
+#ifndef WIN32STDTHREAD_H
+#define WIN32STDTHREAD_H
+
+#include <windows.h>
+#include <functional>
+#include <memory>
+#include <chrono>
+#include <system_error>
+#include <process.h>
+
+#ifdef _GLIBCXX_HAS_GTHREADS
+#error This version of MinGW seems to include a win32 port of pthreads, and probably \
+ already has C++11 std threading classes implemented, based on pthreads. \
+ It is likely that you will get class redefinition errors below, and unfortunately \
+ this implementation can not be used standalone \
+ and independent of the system <mutex> header, since it relies on it for \
+ std::unique_lock and other utility classes. If you would still like to use this \
+ implementation (as it is more lightweight), you have to edit the \
+ c++-config.h system header of your MinGW to not define _GLIBCXX_HAS_GTHREADS. \
+ This will prevent system headers from defining actual threading classes while still \
+ defining the necessary utility classes.
+#endif
+
+//instead of INVALID_HANDLE_VALUE _beginthreadex returns 0
+#define _STD_THREAD_INVALID_HANDLE 0
+namespace std
+{
+
+class thread
+{
+public:
+ class id
+ {
+ DWORD mId;
+ void clear() {mId = 0;}
+ friend class thread;
+ public:
+ id(DWORD aId=0):mId(aId){}
+ bool operator==(const id& other) const {return mId == other.mId;}
+ };
+protected:
+ HANDLE mHandle;
+ id mThreadId;
+public:
+ typedef HANDLE native_handle_type;
+ id get_id() const noexcept {return mThreadId;}
+ native_handle_type native_handle() const {return mHandle;}
+ thread(): mHandle(_STD_THREAD_INVALID_HANDLE){}
+
+ thread(thread&& other)
+ :mHandle(other.mHandle), mThreadId(other.mThreadId)
+ {
+ other.mHandle = _STD_THREAD_INVALID_HANDLE;
+ other.mThreadId.clear();
+ }
+
+ thread(const thread &other)=delete;
+
+ template<class Function, class... Args>
+ explicit thread(Function&& f, Args&&... args)
+ {
+ typedef decltype(std::bind(f, args...)) Call;
+ Call* call = new Call(std::bind(f, args...));
+ mHandle = (HANDLE)_beginthreadex(NULL, 0, threadfunc<Call>,
+ (LPVOID)call, 0, (unsigned*)&(mThreadId.mId));
+ }
+ template <class Call>
+ static unsigned int __stdcall threadfunc(void* arg)
+ {
+ std::unique_ptr<Call> upCall(static_cast<Call*>(arg));
+ (*upCall)();
+ return (unsigned long)0;
+ }
+ bool joinable() const {return mHandle != _STD_THREAD_INVALID_HANDLE;}
+ void join()
+ {
+ if (get_id() == GetCurrentThreadId())
+ throw system_error(EDEADLK, generic_category());
+ if (mHandle == _STD_THREAD_INVALID_HANDLE)
+ throw system_error(ESRCH, generic_category());
+ if (!joinable())
+ throw system_error(EINVAL, generic_category());
+ WaitForSingleObject(mHandle, INFINITE);
+ CloseHandle(mHandle);
+ mHandle = _STD_THREAD_INVALID_HANDLE;
+ mThreadId.clear();
+ }
+
+ ~thread()
+ {
+ if (joinable())
+ std::terminate();
+ }
+ thread& operator=(const thread&) = delete;
+ thread& operator=(thread&& other) noexcept
+ {
+ if (joinable())
+ std::terminate();
+ swap(std::forward<thread>(other));
+ return *this;
+ }
+ void swap(thread&& other) noexcept
+ {
+ std::swap(mHandle, other.mHandle);
+ std::swap(mThreadId.mId, other.mThreadId.mId);
+ }
+ static unsigned int hardware_concurrency() noexcept
+ {
+ static int ncpus = -1;
+ if (ncpus == -1)
+ {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ ncpus = sysinfo.dwNumberOfProcessors;
+ }
+ return ncpus;
+ }
+ void detach()
+ {
+ if (!joinable())
+ throw system_error();
+ if (mHandle != _STD_THREAD_INVALID_HANDLE)
+ {
+ CloseHandle(mHandle);
+ mHandle = _STD_THREAD_INVALID_HANDLE;
+ }
+ mThreadId.clear();
+ }
+};
+
+namespace this_thread
+{
+ inline thread::id get_id() {return thread::id(GetCurrentThreadId());}
+ inline void yield() {Sleep(0);}
+ template< class Rep, class Period >
+ void sleep_for( const std::chrono::duration<Rep,Period>& sleep_duration)
+ {
+ Sleep(chrono::duration_cast<chrono::milliseconds>(sleep_duration).count());
+ }
+ template <class Clock, class Duration>
+ void sleep_until(const std::chrono::time_point<Clock,Duration>& sleep_time)
+ {
+ sleep_for(sleep_time-Clock::now());
+ }
+}
+
+}
+#endif // WIN32STDTHREAD_H