summaryrefslogtreecommitdiff
path: root/zen/thread.h
diff options
context:
space:
mode:
Diffstat (limited to 'zen/thread.h')
-rw-r--r--zen/thread.h90
1 files changed, 65 insertions, 25 deletions
diff --git a/zen/thread.h b/zen/thread.h
index b10dd342..bb6e7901 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -4,19 +4,23 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STD_THREAD_WRAP_H_7896323423432
-#define STD_THREAD_WRAP_H_7896323423432
+#ifndef THREAD_H_7896323423432235246427
+#define THREAD_H_7896323423432235246427
#include <thread>
#include <future>
-#include <zen/scope_guard.h>
-#include <zen/type_traits.h>
+#include "scope_guard.h"
+#include "type_traits.h"
+#include "optional.h"
+#ifdef ZEN_WIN
+#include "win.h"
+#endif
+
namespace zen
{
class InterruptionStatus;
-
class InterruptibleThread
{
public:
@@ -58,6 +62,9 @@ void interruptibleWait(std::condition_variable& cv, std::unique_lock<std::mutex>
template <class Rep, class Period>
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime); //throw ThreadInterruption
+#ifdef ZEN_WIN
+void setCurrentThreadName(const char* threadName);
+#endif
//------------------------------------------------------------------------------------------
/*
@@ -72,7 +79,7 @@ Example:
//dir exising
*/
template <class Function>
-auto runAsync(Function&& fun) -> std::future<decltype(fun())>;
+auto runAsync(Function&& fun);
//wait for all with a time limit: return true if *all* results are available!
template<class InputIterator, class Duration>
@@ -90,18 +97,18 @@ public:
GetFirstResult();
template <class Fun>
- void addJob(Fun&& f); //f must return a std::unique_ptr<T> containing a value if successful
+ void addJob(Fun&& f); //f must return a zen::Opt<T> containing a value if successful
template <class Duration>
bool timedWait(const Duration& duration) const; //true: "get()" is ready, false: time elapsed
//return first value or none if all jobs failed; blocks until result is ready!
- std::unique_ptr<T> get() const; //may be called only once!
+ Opt<T> get() const; //may be called only once!
private:
class AsyncResult;
std::shared_ptr<AsyncResult> asyncResult_;
- size_t jobsTotal_;
+ size_t jobsTotal_ = 0;
};
//------------------------------------------------------------------------------------------
@@ -111,7 +118,7 @@ template <class T>
class Protected
{
public:
- Protected() : value_() {}
+ Protected() {}
Protected(const T& value) : value_(value) {}
template <class Function>
@@ -126,7 +133,7 @@ private:
Protected& operator=(const Protected&) = delete;
std::mutex lockValue;
- T value_;
+ T value_{};
};
@@ -142,7 +149,7 @@ private:
namespace impl
{
template <class Function> inline
-auto runAsync(Function&& fun, TrueType /*copy-constructible*/) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun, TrueType /*copy-constructible*/)
{
typedef decltype(fun()) ResultType;
@@ -155,17 +162,17 @@ auto runAsync(Function&& fun, TrueType /*copy-constructible*/) -> std::future<de
template <class Function> inline
-auto runAsync(Function&& fun, FalseType /*copy-constructible*/) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun, FalseType /*copy-constructible*/)
{
//support move-only function objects!
auto sharedFun = std::make_shared<Function>(std::forward<Function>(fun));
- return runAsync([sharedFun]() { return (*sharedFun)(); }, TrueType());
+ return runAsync([sharedFun] { return (*sharedFun)(); }, TrueType());
}
}
template <class Function> inline
-auto runAsync(Function&& fun) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun)
{
return impl::runAsync(std::forward<Function>(fun), StaticBool<std::is_copy_constructible<Function>::value>());
}
@@ -187,7 +194,7 @@ class GetFirstResult<T>::AsyncResult
{
public:
//context: worker threads
- void reportFinished(std::unique_ptr<T>&& result)
+ void reportFinished(Opt<T>&& result)
{
{
std::lock_guard<std::mutex> dummy(lockResult);
@@ -206,7 +213,7 @@ public:
return conditionJobDone.wait_for(dummy, duration, [&] { return this->jobDone(jobsTotal); });
}
- std::unique_ptr<T> getResult(size_t jobsTotal)
+ Opt<T> getResult(size_t jobsTotal)
{
std::unique_lock<std::mutex> dummy(lockResult);
conditionJobDone.wait(dummy, [&] { return this->jobDone(jobsTotal); });
@@ -226,20 +233,20 @@ private:
#endif
std::mutex lockResult;
- size_t jobsFinished = 0; //
- std::unique_ptr<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
+ size_t jobsFinished = 0; //
+ Opt<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
std::condition_variable conditionJobDone;
};
template <class T> inline
-GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>()), jobsTotal_(0) {}
+GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>()) {}
template <class T>
template <class Fun> inline
-void GetFirstResult<T>::addJob(Fun&& f) //f must return a std::unique_ptr<T> containing a value on success
+void GetFirstResult<T>::addJob(Fun&& f) //f must return a zen::Opt<T> containing a value on success
{
std::thread t([asyncResult = this->asyncResult_, f = std::forward<Fun>(f)] { asyncResult->reportFinished(f()); });
++jobsTotal_;
@@ -253,7 +260,7 @@ bool GetFirstResult<T>::timedWait(const Duration& duration) const { return async
template <class T> inline
-std::unique_ptr<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
+Opt<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
//------------------------------------------------------------------------------------------
@@ -263,7 +270,7 @@ std::unique_ptr<T> GetFirstResult<T>::get() const { return asyncResult_->getResu
#elif defined __GNUC__ || defined __clang__
#define ZEN_THREAD_LOCAL_SPECIFIER __thread
#else
- #error "game over"
+ #error "Game over!"
#endif
@@ -316,7 +323,7 @@ public:
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //throw ThreadInterruption
{
std::unique_lock<std::mutex> lock(lockSleep);
- if (conditionSleepInterruption.wait_for(lock, relTime, [&] { return static_cast<bool>(this->interrupted); }))
+ if (conditionSleepInterruption.wait_for(lock, relTime, [this] { return static_cast<bool>(this->interrupted); }))
throw ThreadInterruption();
}
@@ -406,6 +413,39 @@ InterruptibleThread::InterruptibleThread(Function&& f) : intStatus_(std::make_sh
inline
void InterruptibleThread::interrupt() { intStatus_->interrupt(); }
+
+
+#ifdef ZEN_WIN
+//https://randomascii.wordpress.com/2015/10/26/thread-naming-in-windows-time-for-something-better/
+
+#pragma pack(push,8)
+struct THREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+};
+#pragma pack(pop)
+
+
+inline
+void setCurrentThreadName(const char* threadName)
+{
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+THREADNAME_INFO info = {};
+ info.dwType = 0x1000;
+ info.szName = threadName;
+ info.dwThreadID = GetCurrentThreadId();
+
+ __try
+ {
+ ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER){}
+}
+#endif
}
-#endif //STD_THREAD_WRAP_H_7896323423432
+#endif //THREAD_H_7896323423432235246427
bgstack15