lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
thread.h
00001 /*****************************************************/
00002 /* lean Concurrent              (c) Tobias Zirr 2011 */
00003 /*****************************************************/
00004 
00005 #ifndef LEAN_CONCURRENT_THREAD
00006 #define LEAN_CONCURRENT_THREAD
00007 
00008 #include "../lean.h"
00009 #include "../tags/noncopyable.h"
00010 #include <process.h>
00011 #include <windows.h>
00012 #include <lean/logging/win_errors.h>
00013 
00014 namespace lean
00015 {
00016 namespace concurrent
00017 {
00018 
00020 class thread : public noncopyable
00021 {
00022 private:
00023     HANDLE m_handle;
00024 
00026     template <class Callable>
00027     static unsigned int _stdcall run_thread(void *args)
00028     {
00029         unsigned int result = 0;
00030 
00031         Callable *callable = static_cast<Callable*>(args);
00032         LEAN_ASSERT_NOT_NULL(callable);
00033 
00034         try
00035         {
00036             try
00037             {
00038                 (*callable)();
00039             }
00040             catch (const std::exception &exc)
00041             {
00042                 LEAN_LOG_ERROR_CTX("Unhandled exception during execution of thread", exc.what());
00043                 result = static_cast<unsigned int>(-1);
00044             }
00045             catch (...)
00046             {
00047                 LEAN_LOG_ERROR_MSG("Unhandled exception during execution of thread");
00048                 result = static_cast<unsigned int>(-1);
00049             }
00050 
00051             delete callable;
00052         }
00053         catch (...)
00054         {
00055             result = static_cast<unsigned int>(-2);
00056         }
00057 
00058         return result;
00059     }
00060 
00062     template <class Callable>
00063     static HANDLE run_thread(Callable *callable)
00064     {
00065         LEAN_ASSERT_NOT_NULL(callable);
00066 
00067         HANDLE handle = reinterpret_cast<HANDLE>(
00068                 ::_beginthreadex(nullptr, 0, &run_thread<Callable>, callable, 0, nullptr)
00069             );
00070 
00071         if (handle == NULL)
00072         {
00073             delete callable;
00074             LEAN_THROW_WIN_ERROR_MSG("_beginthreadex() failed");
00075         }
00076 
00077         return handle;
00078     }
00079 
00080 public:
00082     thread()
00083         : m_handle(NULL) { }
00085     template <class Callable>
00086     thread(const Callable &callable)
00087         : m_handle( run_thread( new Callable(callable) ) ) { }
00088 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00089 
00090     template <class Callable>
00091     thread(Callable &&callable)
00092         : m_handle( run_thread( new Callable(std::move(callable)) ) ) { }
00094     thread(thread &&right)
00095         : m_handle(right.m_handle)
00096     {
00097         right.m_handle = NULL;
00098     }
00099 #endif
00100 
00101     ~thread()
00102     {
00103         if (m_handle != NULL)
00104             ::CloseHandle(m_handle);
00105     }
00106 
00107 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00108 
00109     thread& operator =(thread &&right)
00110     {
00111         if (m_handle != right.m_handle)
00112         {
00113             detach();
00114             m_handle = right.m_handle;
00115             right.m_handle = NULL;
00116         }
00117         return *this;
00118     }
00119 #endif
00120 
00122     void detach()
00123     {
00124         if (m_handle != NULL)
00125         {
00126             ::CloseHandle(m_handle);
00127             m_handle = NULL;
00128         }
00129     }
00130 
00132     LEAN_INLINE bool joinable() const
00133     {
00134         return (m_handle != NULL);
00135     }
00137     void join()
00138     {
00139         if (m_handle != NULL)
00140             if (::WaitForSingleObject(m_handle, INFINITE) == WAIT_FAILED)
00141                 LEAN_THROW_WIN_ERROR_MSG("WaitForSingleObject()");
00142     }
00143 
00145     LEAN_INLINE HANDLE native_handle() const
00146     {
00147         return m_handle;
00148     }
00149 };
00150 
00151 } // namespace
00152 
00153 using concurrent::thread;
00154 
00155 } // namespace
00156 
00157 #endif