dlib C++ Library - threads_kernel_1.h

    // Copyright (C) 2003  Davis E. King (davisking@users.sourceforge.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
        {
            // give signaler access to hMutex
            friend class signaler;
        public:

            mutex (
            ) :
                hMutex(CreateMutex(NULL,FALSE,NULL))
            {
                if (hMutex == NULL)
                {
                    throw dlib::thread_error(ECREATE_MUTEX,
            "in function mutex::mutex() an error occurred making the mutex"
                    );
                }
            }

            ~mutex (
            ) { CloseHandle(hMutex); }

            void lock (
            ) const { WaitForSingleObject (hMutex,INFINITE); }

            void unlock (
            ) const { ReleaseMutex(hMutex); }

        private:

            mutable HANDLE hMutex;

            // 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),
                hWaitersMutex(CreateMutex(NULL,FALSE,NULL)),
                hCountSema(CreateSemaphore (NULL,0,100000000,NULL)),
                m(associated_mutex)
            {
                if (hSemaphore == NULL || hWaitersMutex == NULL || hCountSema == NULL)
                {
                    if (hSemaphore != NULL)
                    {
                        CloseHandle(hSemaphore);
                    }

                    if (hWaitersMutex != NULL)
                    {
                        CloseHandle(hWaitersMutex);
                    }

                    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(hWaitersMutex); CloseHandle(hCountSema);}

            void wait (
            ) const
            {
                // get a lock on the mutex for the waiters variable
                WaitForSingleObject (hWaitersMutex,INFINITE);
                // mark that one more thread will be waiting on this signaler
                ++waiters;
                // release the mutex for waiters
                ReleaseMutex(hWaitersMutex);

                // release the assocaited mutex
                ReleaseMutex(m.hMutex);

                // wait for the semaphore to be signaled
                WaitForSingleObject (hSemaphore,INFINITE);

                // signal that we are awake
                ReleaseSemaphore(hCountSema,(LONG)1,NULL);

                // relock the associated mutex
                WaitForSingleObject (m.hMutex,INFINITE);
            }

            bool wait_or_timeout (
                unsigned long milliseconds
            ) const
            {
                // get a lock on the mutex for the waiters variable
                WaitForSingleObject (hWaitersMutex,INFINITE);
                // mark that one more thread will be waiting on this signaler
                ++waiters;
                // release the mutex for waiters
                ReleaseMutex(hWaitersMutex);

                // release the assocaited mutex
                ReleaseMutex(m.hMutex);

                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;

                    // get a lock on the mutex for the waiters variable
                    WaitForSingleObject (hWaitersMutex,INFINITE);
                    // mark that one less thread will be waiting on this signaler.
                    if (waiters != 0)
                        --waiters;
                    // release the mutex for waiters
                    ReleaseMutex(hWaitersMutex);
                }
                else
                {
                    value = true;
                }

                // signal that we are awake
                ReleaseSemaphore(hCountSema,(LONG)1,NULL);

                // relock the associated mutex
                WaitForSingleObject (m.hMutex,INFINITE);

                return value;
            }

            void signal (
            ) const
            {
                // get a lock on the mutex for the waiters variable
                WaitForSingleObject (hWaitersMutex,INFINITE);

                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
                ReleaseMutex(hWaitersMutex);
            }

            void broadcast (
            ) const
            {
                // get a lock on the mutex for the waiters variable
                WaitForSingleObject (hWaitersMutex,INFINITE);

                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
                ReleaseMutex(hWaitersMutex);
            }

            const mutex& get_mutex (
            ) const { return m; }

        private:

            mutable HANDLE hSemaphore;

            mutable unsigned long waiters;
            mutable HANDLE hWaitersMutex;

            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_