00001
00008
00009
00010
00011
00012 #ifndef ECL_THREADS_THREAD_WIN_HPP_
00013 #define ECL_THREADS_THREAD_WIN_HPP_
00014
00015
00016
00017
00018
00019 #include <ecl/config/ecl.hpp>
00020 #if defined(ECL_IS_WIN32)
00021
00022
00023
00024
00025
00026 #include <windows.h>
00027 #include "thread_exceptions_pos.hpp"
00028 #include <ecl/config/macros.hpp>
00029 #include <ecl/concepts/nullary_function.hpp>
00030 #include <ecl/exceptions/standard_exception.hpp>
00031 #include <ecl/utilities/void.hpp>
00032 #include <ecl/utilities/function_objects.hpp>
00033 #include "priority_win.hpp"
00034
00035
00036
00037
00038
00039 namespace ecl {
00040 namespace threads {
00041
00042
00043
00044
00051 class ECL_LOCAL ThreadTaskBase {
00052 public:
00053 virtual ~ThreadTaskBase() {};
00054
00055 protected:
00056 ThreadTaskBase(const Priority& priority) : priority_level(priority) {};
00057 ecl::Priority priority_level;
00058 };
00068 template <typename F, bool IsReferenceWrapper = false>
00069 class ECL_LOCAL ThreadTask : public ThreadTaskBase {
00070 public:
00079 ThreadTask(const F &f, const Priority &priority) : ThreadTaskBase(priority), function(f) {
00080 ecl_compile_time_concept_check(ecl::NullaryFunction<F>);
00081 };
00082 virtual ~ThreadTask() {};
00094 static unsigned int EntryPoint(void *ptr_this) {
00095 ThreadTask< F, false > *ptr = static_cast< ThreadTask< F, false > * >(ptr_this);
00096 (ptr->function)();
00097 return 0;
00098 }
00099
00100 private:
00101 F function;
00102 };
00103
00113 template <typename F>
00114 class ECL_LOCAL ThreadTask<F, true> : public ThreadTaskBase {
00115 public:
00124 ThreadTask(const F &f, const Priority &priority) : ThreadTaskBase(priority), function(f.reference()) {
00125 ecl_compile_time_concept_check(ecl::NullaryFunction< typename F::type>);
00126 };
00127 virtual ~ThreadTask() {};
00138 static unsigned int EntryPoint(void *ptr_this) {
00139 ThreadTask< F, true > *ptr = static_cast< ThreadTask< F, true > * >(ptr_this);
00140 (ptr->function)();
00141 return 0;
00142 }
00143
00144 private:
00145 typename F::type &function;
00146 };
00147
00148 };
00149
00150
00151
00152
00226 class ecl_threads_PUBLIC Thread {
00227 public:
00235 Thread() :
00236 thread_handle(NULL),
00237 thread_task(NULL),
00238 has_started(false),
00239 join_requested(false)
00240 {}
00260 Thread(VoidFunction function, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00270 Error start(VoidFunction function, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00294 template <typename C>
00295 Thread(void (C::*function)(), C &c, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00306 template <typename C>
00307 Error start(void (C::*function)(), C &c, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00308
00347 template <typename F>
00348 Thread(const F &function, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00358 template <typename F>
00359 Error start(const F &function, const Priority &priority = DefaultPriority, const long &stack_size = -1 ) ecl_debug_throw_decl(StandardException);
00360
00369 virtual ~Thread();
00370
00376 bool isRunning() { if ( thread_task == NULL ) { return false; } else { return true; } }
00377
00391 void cancel() ecl_debug_throw_decl(StandardException);
00392
00400 void join() ecl_assert_throw_decl(StandardException);
00401
00402
00403 private:
00404 HANDLE thread_handle;
00405 threads::ThreadTaskBase *thread_task;
00406 bool has_started;
00407 bool join_requested;
00408
00409 void initialise(const long &stack_size) ecl_assert_throw_decl(StandardException);
00410
00411 enum ThreadProperties {
00412 DefaultStackSize = -1
00413 };
00414 };
00415
00416
00417
00418
00419
00420 template <typename C>
00421 Thread::Thread(void (C::*function)(), C &c, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException) :
00422 thread_handle(NULL),
00423 thread_task(NULL),
00424 has_started(false),
00425 join_requested(false)
00426 {
00427 start<C>(function, c, priority, stack_size);
00428
00429 }
00430
00431 template <typename F>
00432 Thread::Thread(const F &function, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException) :
00433 thread_handle(NULL),
00434 thread_task(NULL),
00435 has_started(false),
00436 join_requested(false)
00437 {
00438 start<F>(function, priority, stack_size);
00439 }
00440
00441 template <typename C>
00442 Error Thread::start(void (C::*function)(), C &c, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException)
00443 {
00444
00445
00446 if ( has_started ) {
00447 ecl_debug_throw(StandardException(LOC,BusyError,"The thread has already been started."));
00448 return Error(BusyError);
00449 } else {
00450 has_started = true;
00451 }
00452
00453 thread_task = new threads::ThreadTask< BoundNullaryMemberFunction<C,void> >(generateFunctionObject( function, c ), priority);
00454
00455 DWORD threadid;
00456
00457 thread_handle = CreateThread(NULL,
00458 0,
00459 (LPTHREAD_START_ROUTINE)threads::ThreadTask< BoundNullaryMemberFunction<C,void> >::EntryPoint,
00460 thread_task,
00461 0,
00462 &threadid);
00463
00464 if (!thread_handle) {
00465 ecl_debug_throw(StandardException(LOC, UnknownError, "Failed to create thread."));
00466 return Error(UnknownError);
00467 }
00468
00469 BOOL bResult = FALSE;
00470
00471 if (priority >= RealTimePriority1) {
00472 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_TIME_CRITICAL);
00473 }
00474
00475 switch (priority) {
00476 case CriticalPriority:
00477 bResult = SetThreadPriority(thread_handle, HIGH_PRIORITY_CLASS);
00478 break;
00479 case HighPriority:
00480 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_ABOVE_NORMAL);
00481 break;
00482 case LowPriority:
00483 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_BELOW_NORMAL);
00484 break;
00485 case BackgroundPriority:
00486 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_IDLE);
00487 break;
00488 default:
00489 break;
00490 }
00491
00492 if (!bResult) {
00493 ecl_debug_throw(threads::throwPriorityException(LOC));
00494 }
00495
00496 return Error(NoError);
00497 }
00498
00499 template <typename F>
00500 Error Thread::start(const F &function, const Priority &priority, const long &stack_size) ecl_debug_throw_decl(StandardException)
00501 {
00502
00503
00504 if ( has_started ) {
00505 ecl_debug_throw(StandardException(LOC,BusyError,"The thread has already been started."));
00506 return Error(BusyError);
00507 } else {
00508 has_started = true;
00509 }
00510
00511 thread_task = new threads::ThreadTask<F, is_reference_wrapper<F>::value >(function, priority);
00512
00513 DWORD threadid;
00514
00515 thread_handle = CreateThread(NULL,
00516 0,
00517 (LPTHREAD_START_ROUTINE)threads::ThreadTask<F, is_reference_wrapper<F>::value >::EntryPoint,
00518 thread_task,
00519 0,
00520 &threadid);
00521
00522 if (!thread_handle) {
00523 ecl_debug_throw(StandardException(LOC, UnknownError, "Failed to create thread."));
00524 return Error(UnknownError);
00525 }
00526
00527 BOOL bResult = FALSE;
00528
00529 if (priority >= RealTimePriority1) {
00530 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_TIME_CRITICAL);
00531 }
00532
00533 switch (priority) {
00534 case CriticalPriority:
00535 bResult = SetThreadPriority(thread_handle, HIGH_PRIORITY_CLASS);
00536 break;
00537 case HighPriority:
00538 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_ABOVE_NORMAL);
00539 break;
00540 case LowPriority:
00541 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_BELOW_NORMAL);
00542 break;
00543 case BackgroundPriority:
00544 bResult = SetThreadPriority(thread_handle, THREAD_PRIORITY_IDLE);
00545 break;
00546 default:
00547 break;
00548 }
00549
00550 if (!bResult) {
00551 ecl_debug_throw(threads::throwPriorityException(LOC));
00552 }
00553
00554 return Error(NoError);
00555 }
00556
00557 };
00558
00559 #endif
00560 #endif