// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_THREADS_KERNEl_1_ #define DLIB_THREADS_KERNEl_1_ #ifdef DLIB_ISO_CPP_ONLY #error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." #endif #include "threads_kernel_abstract.h" #include "../windows_magic.h" #include <windows.h> #include "../algs.h" namespace dlib { // ---------------------------------------------------------------------------------------- typedef DWORD thread_id_type; inline thread_id_type get_thread_id ( ) { return GetCurrentThreadId(); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // mutex object // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // forward declaration of signaler class signaler; class mutex { public: mutex ( ) { InitializeCriticalSection(&cs); } ~mutex ( ) { DeleteCriticalSection(&cs); } void lock ( ) const { EnterCriticalSection(&cs); } void unlock ( ) const { LeaveCriticalSection(&cs); } private: mutable CRITICAL_SECTION cs; // restricted functions mutex(mutex&); // copy constructor mutex& operator=(mutex&); // assignment operator }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // signaler object // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class signaler { public: signaler ( const mutex& associated_mutex ) : hSemaphore(CreateSemaphore (NULL, 0, 100000000, NULL)), waiters(0), hCountSema(CreateSemaphore (NULL,0,100000000,NULL)), m(associated_mutex) { if (hSemaphore == NULL || hCountSema == NULL) { if (hSemaphore != NULL) { CloseHandle(hSemaphore); } if (hCountSema != NULL) { CloseHandle(hCountSema); } throw dlib::thread_error(ECREATE_SIGNALER, "in function signaler::signaler() an error occurred making the signaler" ); } } ~signaler ( ) { CloseHandle(hSemaphore); CloseHandle(hCountSema);} void wait ( ) const { // get a lock on the mutex for the waiters variable waiters_mutex.lock(); // mark that one more thread will be waiting on this signaler ++waiters; // release the mutex for waiters waiters_mutex.unlock(); // release the associated mutex m.unlock(); // wait for the semaphore to be signaled WaitForSingleObject (hSemaphore,INFINITE); // signal that we are awake ReleaseSemaphore(hCountSema,(LONG)1,NULL); // relock the associated mutex m.lock(); } bool wait_or_timeout ( unsigned long milliseconds ) const { // get a lock on the mutex for the waiters variable waiters_mutex.lock(); // mark that one more thread will be waiting on this signaler ++waiters; // release the mutex for waiters waiters_mutex.unlock(); // release the associated mutex m.unlock(); bool value; // wait for the semaphore to be signaled if ( WaitForSingleObject (hSemaphore, milliseconds ) == WAIT_TIMEOUT ) { // in this case we should decrement waiters because we are returning // due to a timeout rather than because someone called signal() or // broadcast(). value = false; // signal that we are awake ReleaseSemaphore(hCountSema,(LONG)1,NULL); // get a lock on the mutex for the waiters variable waiters_mutex.lock(); // mark that one less thread will be waiting on this signaler. if (waiters != 0) --waiters; // release the mutex for waiters waiters_mutex.unlock(); } else { value = true; // signal that we are awake ReleaseSemaphore(hCountSema,(LONG)1,NULL); } // relock the associated mutex m.lock(); return value; } void signal ( ) const { // get a lock on the mutex for the waiters variable waiters_mutex.lock(); if (waiters > 0) { --waiters; // make the semaphore release one waiting thread ReleaseSemaphore(hSemaphore,1,NULL); // wait for signaled thread to wake up WaitForSingleObject(hCountSema,INFINITE); } // release the mutex for waiters waiters_mutex.unlock(); } void broadcast ( ) const { // get a lock on the mutex for the waiters variable waiters_mutex.lock(); if (waiters > 0) { // make the semaphore release all the waiting threads ReleaseSemaphore(hSemaphore,(LONG)waiters,NULL); // wait for count to be zero for (unsigned long i = 0; i < waiters; ++i) { WaitForSingleObject(hCountSema,INFINITE); } waiters = 0; } // release the mutex for waiters waiters_mutex.unlock(); } const mutex& get_mutex ( ) const { return m; } private: mutable HANDLE hSemaphore; mutable unsigned long waiters; mutex waiters_mutex; mutable HANDLE hCountSema; const mutex& m; // restricted functions signaler(signaler&); // copy constructor signaler& operator=(signaler&); // assignment operator }; // ---------------------------------------------------------------------------------------- namespace threads_kernel_shared_helpers { bool spawn_thread ( void (*funct)(void*), void* param ); /*! is identical to create_new_thread() but just doesn't use any thread pooling. !*/ } // ---------------------------------------------------------------------------------------- } #include "threads_kernel_shared.h" #ifdef NO_MAKEFILE #include "threads_kernel_1.cpp" #endif #endif // DLIB_THREADS_KERNEl_1_