$search
00001 // 00002 // win_thread.hpp 00003 // ~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #ifndef ASIO_DETAIL_WIN_THREAD_HPP 00012 #define ASIO_DETAIL_WIN_THREAD_HPP 00013 00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00015 # pragma once 00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00017 00018 #include "asio/detail/push_options.hpp" 00019 00020 #include "asio/detail/push_options.hpp" 00021 #include <boost/config.hpp> 00022 #include "asio/detail/pop_options.hpp" 00023 00024 #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) 00025 00026 #include "asio/error.hpp" 00027 #include "asio/system_error.hpp" 00028 #include "asio/detail/noncopyable.hpp" 00029 #include "asio/detail/socket_types.hpp" 00030 00031 #include "asio/detail/push_options.hpp" 00032 #include <boost/throw_exception.hpp> 00033 #include <memory> 00034 #include <process.h> 00035 #include "asio/detail/pop_options.hpp" 00036 00037 namespace asio { 00038 namespace detail { 00039 00040 unsigned int __stdcall win_thread_function(void* arg); 00041 00042 class win_thread 00043 : private noncopyable 00044 { 00045 public: 00046 // The purpose of the thread. 00047 enum purpose { internal, external }; 00048 00049 // Constructor. 00050 template <typename Function> 00051 win_thread(Function f, purpose p = internal) 00052 : exit_event_(0) 00053 { 00054 std::auto_ptr<func_base> arg(new func<Function>(f)); 00055 00056 ::HANDLE entry_event = 0; 00057 if (p == internal) 00058 { 00059 arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); 00060 if (!entry_event) 00061 { 00062 DWORD last_error = ::GetLastError(); 00063 asio::system_error e( 00064 asio::error_code(last_error, 00065 asio::error::get_system_category()), 00066 "thread.entry_event"); 00067 boost::throw_exception(e); 00068 } 00069 00070 arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); 00071 if (!exit_event_) 00072 { 00073 DWORD last_error = ::GetLastError(); 00074 ::CloseHandle(entry_event); 00075 asio::system_error e( 00076 asio::error_code(last_error, 00077 asio::error::get_system_category()), 00078 "thread.exit_event"); 00079 boost::throw_exception(e); 00080 } 00081 } 00082 00083 unsigned int thread_id = 0; 00084 thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0, 00085 win_thread_function, arg.get(), 0, &thread_id)); 00086 if (!thread_) 00087 { 00088 DWORD last_error = ::GetLastError(); 00089 if (entry_event) 00090 ::CloseHandle(entry_event); 00091 if (exit_event_) 00092 ::CloseHandle(exit_event_); 00093 asio::system_error e( 00094 asio::error_code(last_error, 00095 asio::error::get_system_category()), 00096 "thread"); 00097 boost::throw_exception(e); 00098 } 00099 arg.release(); 00100 00101 if (entry_event) 00102 { 00103 ::WaitForSingleObject(entry_event, INFINITE); 00104 ::CloseHandle(entry_event); 00105 } 00106 } 00107 00108 // Destructor. 00109 ~win_thread() 00110 { 00111 ::CloseHandle(thread_); 00112 00113 // The exit_event_ handle is deliberately allowed to leak here since it 00114 // is an error for the owner of an internal thread not to join() it. 00115 } 00116 00117 // Wait for the thread to exit. 00118 void join() 00119 { 00120 if (exit_event_) 00121 { 00122 ::WaitForSingleObject(exit_event_, INFINITE); 00123 ::CloseHandle(exit_event_); 00124 ::TerminateThread(thread_, 0); 00125 } 00126 else 00127 { 00128 ::WaitForSingleObject(thread_, INFINITE); 00129 } 00130 } 00131 00132 private: 00133 friend unsigned int __stdcall win_thread_function(void* arg); 00134 00135 class func_base 00136 { 00137 public: 00138 virtual ~func_base() {} 00139 virtual void run() = 0; 00140 ::HANDLE entry_event_; 00141 ::HANDLE exit_event_; 00142 }; 00143 00144 template <typename Function> 00145 class func 00146 : public func_base 00147 { 00148 public: 00149 func(Function f) 00150 : f_(f) 00151 { 00152 } 00153 00154 virtual void run() 00155 { 00156 f_(); 00157 } 00158 00159 private: 00160 Function f_; 00161 }; 00162 00163 ::HANDLE thread_; 00164 ::HANDLE exit_event_; 00165 }; 00166 00167 inline unsigned int __stdcall win_thread_function(void* arg) 00168 { 00169 std::auto_ptr<win_thread::func_base> func( 00170 static_cast<win_thread::func_base*>(arg)); 00171 00172 if (func->entry_event_) 00173 ::SetEvent(func->entry_event_); 00174 00175 func->run(); 00176 00177 if (HANDLE exit_event = func->exit_event_) 00178 { 00179 func.reset(); 00180 ::SetEvent(exit_event); 00181 ::Sleep(INFINITE); 00182 } 00183 00184 return 0; 00185 } 00186 00187 } // namespace detail 00188 } // namespace asio 00189 00190 #endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) 00191 00192 #include "asio/detail/pop_options.hpp" 00193 00194 #endif // ASIO_DETAIL_WIN_THREAD_HPP