| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 | 
							- // threading.cpp
 - //
 - // Copyright (C) 2006-2020 MicroNeil Research Corporation.
 - //
 - // This software is released under the MIT license. See LICENSE.TXT.
 - 
 - #include "threading.hpp"
 - 
 - namespace codedweller {
 - 
 - ThreadManager Threads;                                                          // Master thread manager.
 - 
 - void ThreadManager::rememberThread(Thread* T) {                                 // Threads register themselves.
 -     ScopeMutex ThereCanBeOnlyOne(MyMutex);                                      // Protect the known pool.
 -     KnownThreads.insert(T);                                                     // Add the new thread pointer.
 - }
 - 
 - void ThreadManager::forgetThread(Thread* T) {                                   // Threads remove themselves.
 -     ScopeMutex ThereCanBeOnlyOne(MyMutex);                                      // Protect the known pool.
 -     KnownThreads.erase(T);                                                      // Add the new thread pointer.
 - }
 - 
 - ThreadStatusReport ThreadManager::StatusReport() {                              // Get a status report, All Threads.
 -     ScopeMutex ThereCanBeOnlyOne(MyMutex);                                      // Protect our set -- a moment in time.
 -     ThreadStatusReport Answer;                                                  // Create our vector to hold the report.
 -     for(                                                                        // Loop through all of the Threads.
 -       std::set<Thread*>::iterator iT = KnownThreads.begin();
 -       iT != KnownThreads.end(); iT++
 -       ) {                                                                       // Grab each Threads' report.
 -         Thread& X = *(*iT);                                                     // Handy reference to the Thread.
 -         Answer.push_back(X.StatusReport());                                     // Push back each Thread's report.
 -     }
 -     return Answer;                                                              // Return the finished report.
 - }
 - 
 - bool ThreadManager::lockExistingThread(Thread* T) {                             // Locks ThreadManager if T exists.
 -     MyMutex.lock();                                                             // Lock the mutex for everyone.
 -     if(KnownThreads.end() == KnownThreads.find(T)) {                            // If we do not find T in our set
 -         MyMutex.unlock();                                                       // then unlock the mutex and return
 -         return false;                                                           // false.
 -     }                                                                           // If we did find it then
 -     LockedThread = T;                                                           // set our locked thread and
 -     return true;                                                                // return true;
 - }
 - 
 - const RuntimeCheck ThreadingCheck1("ThreadManager::unlockExistingThread():ThreadingCheck1(0 != LockedThread)");
 - const RuntimeCheck ThreadingCheck2("ThreadManager::unlockExistingThread():ThreadingCheck2(T == LockedThread)");
 - 
 - void ThreadManager::unlockExistingThread(Thread* T) {                           // Unlocks ThreadManager if T locked.
 -     ThreadingCheck1(0 != LockedThread);                                         // We had better have a locked thread.
 -     ThreadingCheck2(T == LockedThread);                                         // The locked thread had better match.
 -     LockedThread = 0;                                                           // Clear the locked thread.
 -     MyMutex.unlock();                                                           // Unlock the mutex.
 - }
 - 
 - //// Scope Thread Lock allows for a safe way to lock threads through the Threads
 - //// object for delivering short messages. Just like a ScopeMutex, when the object
 - //// goes away the lock is released.
 - 
 - ScopeThreadLock::ScopeThreadLock(Thread* T) :                                   // Construct a scope lock on a Thread.
 -   MyLockedThread(0) {                                                           // To star with we have no lock.
 -     if(Threads.lockExistingThread(T)) {                                         // If we achieve a lock then we
 -         MyLockedThread = T;                                                     // remember it. Our destructor will
 -     }                                                                           // unlock it if we were successful.
 - }
 - 
 - ScopeThreadLock::~ScopeThreadLock() {                                           // Destruct a scope lock on a Thread.
 -     if(0 != MyLockedThread) {                                                   // If we were successfully constructed
 -         Threads.unlockExistingThread(MyLockedThread);                           // we can unlock the thread and
 -         MyLockedThread = 0;                                                     // forget about it before we go away.
 -     }
 - }
 - 
 - bool ScopeThreadLock::isGood() {                                                // If we have successfully locked T
 -     return (0 != MyLockedThread) ? true:false;                                  // it will NOT be 0, so return true.
 - }
 - 
 - bool ScopeThreadLock::isBad() {                                                 // If we did not successfully lock T
 -     return (0 == MyLockedThread) ? false:true;                                  // it will be 0, so return false.
 - }
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // Thread
 - 
 - const ThreadType  Thread::Type("Generic Thread");
 - const ThreadState Thread::ThreadInitialized("Thread Initialized");
 - const ThreadState Thread::ThreadStarted("Thread Started");
 - const ThreadState Thread::ThreadFailed("Thread Failed");
 - const ThreadState Thread::ThreadStopped("Thread Stopped");
 - const ThreadState Thread::ThreadDestroyed("Thread Destroyed");
 - 
 - bool Thread::isRunning() { return RunningFlag; }                                // Return RunningFlag state.
 - 
 - bool Thread::isBad() { return BadFlag; }                                        // Return BadFlag state.
 - 
 - const std::string Thread::MyFault() { return BadWhat; }                         // Return exception Bad fault if any.
 - const std::string Thread::MyName() { return MyThreadName; }                     // Return the instance name if any.
 - const ThreadType& Thread::MyType() { return MyThreadType; }                     // Return the instance Thread Type.
 - const ThreadState& Thread::MyState() { return (*MyThreadState); }               // Thread state for this instance.
 - 
 - void Thread::CurrentThreadState(const ThreadState& TS) {                        // Set Current Thread State.
 -     MyThreadState = const_cast<ThreadState*>(&TS);
 - }
 - 
 - const ThreadState& Thread::CurrentThreadState() { return (*MyThreadState); }    // Get Current Thread State.
 - 
 - ThreadStatusRecord Thread::StatusReport() {                                     // Get a status report from this thread.
 -     return
 -       ThreadStatusRecord(                                                       // Status record.
 -         this,
 -         const_cast<ThreadType&>(MyThreadType),
 -         *MyThreadState,
 -         RunningFlag,
 -         BadFlag,
 -         BadWhat,
 -         MyThreadName
 -       );
 - }
 - 
 - // launchTask() calls and monitors myTask for exceptions and set's the correct
 - // states for the isBad and isRunning flags.
 - 
 - void Thread::launchTask() {                                                     // Launch and watch myTask()
 -     try {                                                                       // Do this safely.
 -         RunningFlag = true;                                                     // Now we are running.
 -         CurrentThreadState(ThreadStarted);                                      // Set the running state.
 -         myTask();                                                               // myTask() is called.
 -     }                                                                           // myTask() should handle exceptions.
 -     catch(const std::exception& e) {                                            // Unhandled exceptions are informative:
 -         BadFlag = true;                                                         // They mean the thread went bad but
 -         BadWhat = e.what();                                                     // we have an idea what went wrong.
 -     }                                                                           // We shouldn't get other kinds of
 -     catch(...) {                                                                // exceptions because if things go
 -         BadFlag = true;                                                         // wrong and one gets through this
 -         BadWhat = "Unkown Exception(...)";                                      // is all we can say about it.
 -     }
 -     RunningFlag = false;                                                        // When we're done, we're done.
 -     if(BadFlag) CurrentThreadState(ThreadFailed);                               // If we're bad we failed.
 -     else CurrentThreadState(ThreadStopped);                                     // If we're not bad we stopped.
 - }
 - 
 - // getMyThread() returns the local thread primative.
 - 
 - thread_primative Thread::getMyThread() { return MyThread; }                     // Return my thread primative.
 - 
 - // runThreadTask() is a helper function to start threads. It is the function
 - // that is acutally launched as a new thread. It's whole job is to call the
 - // myTask() method on the object passed to it as it is launched.
 - 
 - // The run() method creates a new thread with ThreadRunner() as the main
 - // function, having passed it's object.
 - 
 - // WIN32 and POSIX have different versions of both the main thread function
 - // and the way to launch it.
 - 
 - #ifdef WIN32
 - 
 - Thread::Thread() :                                                              // When constructing a WIN32 thread
 -   MyThreadType(Thread::Type),                                                   // Use generic Thread Type.
 -   MyThreadName("UnNamed Thread"),                                               // Use a generic Thread Name.
 -   MyThread(NULL),                                                               // Null the thread handle.
 -   RunningFlag(false),                                                           // Couldn't be running yet.
 -   BadFlag(false) {                                                              // Couldn't be bad yet.
 -     Threads.rememberThread(this);                                               // Remember this thread.
 -     CurrentThreadState(ThreadInitialized);                                      // Set our initialized state.
 - }
 - 
 - Thread::Thread(const ThreadType& T, const std::string N) :                      // Construct with specific Type/Name
 -   MyThreadType(T),                                                              // Use generic Thread Type.
 -   MyThreadName(N),                                                              // Use a generic Thread Name.
 -   MyThread(NULL),                                                               // Null the thread handle.
 -   RunningFlag(false),                                                           // Couldn't be running yet.
 -   BadFlag(false) {                                                              // Couldn't be bad yet.
 -     Threads.rememberThread(this);                                               // Remember this thread.
 -     CurrentThreadState(ThreadInitialized);                                      // Set our initialized state.
 - }
 - 
 - Thread::~Thread() {                                                             // In WIN32 land when we destroy the
 -     if(NULL != MyThread) {                                                      // thread object check for a valid
 -         CloseHandle(MyThread);                                                  // thread handle and destroy it if
 -     }                                                                           // it exists.
 -     RunningFlag = false;                                                        // The thread is not running.
 -     Threads.forgetThread(this);                                                 // Forget this thread.
 -     CurrentThreadState(ThreadDestroyed);                                        // The Thread has left the building.
 - }
 - 
 - unsigned __stdcall runThreadTask(void* thread_object) {                         // The WIN32 version has this form.
 -     ((Thread*)thread_object)->launchTask();                                     // Run the task.
 -     _endthreadex(0);                                                            // Signal the thread is finished.
 -     return 0;                                                                   // Satisfy the unsigned return.
 - }
 - 
 - void Thread::run() {                                                            // Run a WIN32 thread...
 -     unsigned tid;                                                               // Thread id to toss. Only need Handle.
 -     MyThread = (HANDLE) _beginthreadex(NULL,0,runThreadTask,this,0,&tid);       // Create a thread calling ThreadRunner
 -     if(NULL == MyThread) BadFlag = true;                                        // and test that the resutl was valid.
 - }
 - 
 - void Thread::join() {                                                           // To join in WIN32
 -     WaitForSingleObject(MyThread, INFINITE);                                    // Wait for the thread by handle.
 - }
 - 
 - #else
 - 
 - Thread::Thread() :                                                              // POSIX Thread constructor.
 -   MyThreadType(Thread::Type),                                                   // Use a generic Thread Type.
 -   MyThreadName("UnNamed Thread"),                                               // Use a generic Thread Name.
 -   RunningFlag(false),                                                           // Can't be running yet.
 -   BadFlag(false) {                                                              // Can't be bad yet.
 -     Threads.rememberThread(this);                                               // Remember this thread.
 -     CurrentThreadState(ThreadInitialized);                                      // Set our initialized state.
 - }
 - 
 - Thread::Thread(const ThreadType& T, const std::string N) :                      // POSIX Specific Thread Constructor.
 -   MyThreadType(T),                                                              // Use a generic Thread Type.
 -   MyThreadName(N),                                                              // Use a generic Thread Name.
 -   RunningFlag(false),                                                           // Can't be running yet.
 -   BadFlag(false) {                                                              // Can't be bad yet.
 -     Threads.rememberThread(this);                                               // Remember this thread.
 -     CurrentThreadState(ThreadInitialized);                                      // Set our initialized state.
 - }
 - 
 - Thread::~Thread() {                                                             // POSIX destructor.
 -     RunningFlag = false;                                                        // Not running now for sure.
 -     Threads.forgetThread(this);                                                 // Forget this thread.
 -     CurrentThreadState(ThreadDestroyed);                                        // The Thread has left the building.
 - }
 - 
 - void* runThreadTask(void* thread_object) {                                      // The POSIX version has this form.
 -     ((Thread*)thread_object)->launchTask();
 -     return NULL;
 - }
 - 
 - void Thread::run() {                                                            // Run a POSIX thread...
 -     int result = pthread_create(&MyThread, NULL, runThreadTask, this);          // Create a thread calling ThreadRunner
 -     if(0 != result) BadFlag = true;                                             // and test that there was no error.
 - }
 - 
 - void Thread::join() {                                                           // To join in POSIX
 -     pthread_join(MyThread, NULL);                                               // call pthread_join with MyThread.
 - }
 - 
 - #endif
 - 
 - // End Thread
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // Mutex
 - 
 - #ifdef WIN32
 - 
 - // WIN32 Mutex Implementation //////////////////////////////////////////////////
 - 
 - // The original design of the WIN32 Mutex used critical sections. However after
 - // additional research it was determined that the use of a Semaphore with an
 - // initial count of 1 would work better overall on multiple Winx platforms -
 - // especially SMP systems.
 - 
 - const RuntimeCheck ThreadingCheck3("Mutex::Mutex():ThreadingCheck3(NULL != MyMutex)");
 - 
 - Mutex::Mutex() :                                                                // Creating a WIN32 Mutex means
 -   IAmLocked(false) {                                                            // Setting IAmLocked to false and
 -     MyMutex = CreateSemaphore(NULL, 1, 1, NULL);                                // create a semaphore object with
 -     ThreadingCheck3(NULL != MyMutex);                                           // a count of 1.
 - }
 - 
 - const ExitCheck ThreadingCheck4("Mutex::~Mutex():");
 - 
 - Mutex::~Mutex() {                                                               // Destroying a WIN32 Mutex means
 -     ThreadingCheck4(false == IAmLocked);                                        // Make sure we're not in use and
 -     CloseHandle(MyMutex);                                                       // destroy the semaphore object.
 - }
 - 
 - bool Mutex::tryLock() {                                                         // Trying to lock WIN32 Mutex means
 -     bool DoIHaveIt = false;                                                     // Start with a pessimistic assumption
 -     if(
 -       false == IAmLocked &&                                                     // If we have a shot at this and
 -       WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, 0)                          // we actually get hold of the semaphore
 -       ) {                                                                       // then we can set our flags...
 -           IAmLocked = true;                                                     // Set IAmLocked, because we are and
 -           DoIHaveIt = true;                                                     // set our result to true.
 -     }
 -     return DoIHaveIt;                                                           // Return true if we got it (see above).
 - }
 - 
 - const RuntimeCheck ThreadingCheck5("Mutex::lock():ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE))");
 - 
 - void Mutex::lock() {                                                            // Locking the WIN32 Mutex means
 -     ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE));   // Wait on the semaphore - only 1 will
 -     IAmLocked = true;                                                           // get through or we have a big problem.
 - }
 - 
 - const LogicCheck ThreadingCheck6("Mutex::unlock():ThreadingCheck6(true == IAmLocked)");
 - 
 - void Mutex::unlock() {                                                          // Unlocking the WIN32 Mutex means
 -     ThreadingCheck6(true == IAmLocked);                                         // making sure we're really locked then
 -     IAmLocked = false;                                                          // reset the IAmLocked flag and
 -     ReleaseSemaphore(MyMutex, 1, NULL);                                         // release the semaphore.
 - }
 - 
 - bool Mutex::isLocked() { return IAmLocked; }                                    // Return the IAmLocked flag.
 - 
 - #else
 - 
 - // POSIX Mutex Implementation //////////////////////////////////////////////////
 - 
 - const RuntimeCheck ThreadingCheck7("Mutex::Mutex():ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL))");
 - 
 - Mutex::Mutex() :                                                                // Constructing a POSIX mutex means
 -   IAmLocked(false) {                                                            // setting the IAmLocked flag to false and
 -     ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL));                    // initializing the mutex_t object.
 - }
 - 
 - const ExitCheck ThreadingCheck8("Mutex::~Mutex():ThreadingCheck8(false == IAmLocked)");
 - const ExitCheck ThreadingCheck9("Mutex::~Mutex():ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex))");
 - 
 - Mutex::~Mutex() {                                                               // Before we destroy our mutex we check
 -     ThreadingCheck8(false == IAmLocked);                                        // to see that it is not locked and
 -     ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex));                      // destroy the primative.
 - }
 - 
 - const RuntimeCheck ThreadingCheck10("Mutex::lock():ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex));");
 - 
 - void Mutex::lock() {                                                            // Locking a POSIX mutex means
 -     ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex));                        // asserting our lock was successful and
 -     IAmLocked = true;                                                           // setting the IAmLocked flag.
 - }
 - 
 - const LogicCheck ThreadingCheck11("Mutex::unlock():ThreadingCheck11(true == IAmLocked)");
 - const RuntimeCheck ThreadingCheck12("Mutex::unlock():ThreadingCheck12(0 == pthread_mutex_unlock(&MyMutex))");
 - 
 - void Mutex::unlock() {                                                          // Unlocking a POSIX mutex means
 -     ThreadingCheck11(true == IAmLocked);                                        // asserting that we are locked,
 -     IAmLocked = false;                                                          // clearing the IAmLocked flag, and
 -     ThreadingCheck12(0 == pthread_mutex_unlock(&MyMutex));                      // unlocking the actual mutex.
 - }
 - 
 - bool Mutex::tryLock() {                                                         // Trying to lock a POSIX mutex means
 -     bool DoIHaveIt = false;                                                     // starting off pessimistically.
 -     if(false == IAmLocked) {                                                    // If we are not locked yet then we
 -         if(0 == pthread_mutex_trylock(&MyMutex)) {                              // try to lock the mutex. If we succeed
 -             IAmLocked = true;                                                   // we set our IAmLocked flag and our
 -             DoIHaveIt = true;                                                   // DoIHaveIt flag to true;
 -         }
 -     }
 -     return DoIHaveIt;                                                           // In any case we return the result.
 - }
 - 
 - bool Mutex::isLocked() { return IAmLocked; }                                    // Return the IAmLocked flag.
 - 
 - #endif
 - 
 - // End Mutex
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // ScopeMutex
 - 
 - ScopeMutex::ScopeMutex(Mutex& M) :                                              // When constructing a ScopeMutex,
 -   MyMutex(M) {                                                                  // Initialize MyMutex with what we are given
 -     MyMutex.lock();                                                             // and then immediately lock it.
 - }
 - 
 - ScopeMutex::~ScopeMutex() {                                                     // When a ScopeMutex is destroyed,
 -     MyMutex.unlock();                                                           // it first unlocks it's mutex.
 - }
 - 
 - // End ScopeMutex
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // Production Gateway
 - 
 - #ifdef WIN32
 - 
 - // Win32 Implementation ////////////////////////////////////////////////////////
 - 
 - const RuntimeCheck ThreadingCheck13("ProductionGateway::ProductionGateway():ThreadingCheck13(NULL != MySemaphore)");
 - 
 - ProductionGateway::ProductionGateway() {                                        // Construct in Windows like this:
 -     const int HUGENUMBER = 0x7fffffL;                                           // Work without any real limits.
 -     MySemaphore = CreateSemaphore(NULL, 0, HUGENUMBER, NULL);                   // Create a Semaphore for signalling.
 -     ThreadingCheck13(NULL != MySemaphore);                                      // That should always work.
 - }
 - 
 - ProductionGateway::~ProductionGateway() {                                       // Be sure to close it when we're done.
 -     CloseHandle(MySemaphore);
 - }
 - 
 - void ProductionGateway::produce() {                                             // To produce() in WIN32 we
 -     ReleaseSemaphore(MySemaphore, 1, NULL);                                     // release 1 count into the semaphore.
 - }
 - 
 - void ProductionGateway::consume() {                                             // To consume() in WIN32 we
 -     WaitForSingleObject(MySemaphore, INFINITE);                                 // wait for a count in the semaphore.
 - }
 - 
 - #else
 - 
 - // POSIX Implementation ////////////////////////////////////////////////////////
 - 
 - const RuntimeCheck ThreadingCheck14("ProductionGateway::ProductionGateway():ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL));");
 - const RuntimeCheck ThreadingCheck15("ProductionGateway::ProductionGateway():ThreadingCheck15(0 == pthread_cond_init(&MyConditionVariable, NULL))");
 - 
 - ProductionGateway::ProductionGateway() :                                        // Construct in POSIX like this:
 -   Product(0),                                                                   // All of our counts start at zero.
 -   Waiting(0),
 -   Signaled(0) {
 -     ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL));                  // Initialize our mutex.
 -     ThreadingCheck15(0 == pthread_cond_init(&MyConditionVariable, NULL));       // Initialize our condition variable.
 - }
 - 
 - const ExitCheck ThreadingCheck16("ProductionGateway::~ProductionGateway():ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex))");
 - const ExitCheck ThreadingCheck17("ProductionGateway::~ProductionGateway():ThreadingCheck17(0 == pthread_cond_destroy(&MyConditionVariable))");
 - 
 - ProductionGateway::~ProductionGateway() {                                       // When we're done we must destroy
 -     ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex));                     // our local mutex and
 -     ThreadingCheck17(0 == pthread_cond_destroy(&MyConditionVariable));          // our condition variable.
 - }
 - 
 - const RuntimeCheck ThreadingCheck18("ProductionGateway::produce():ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex))");
 - const RuntimeCheck ThreadingCheck19("ProductionGateway::produce():ThreadingCheck19(0 == pthread_cond_signal(&MyConditionVariable))");
 - const RuntimeCheck ThreadingCheck20("ProductionGateway::produce():ThreadingCheck20(0 == pthread_mutex_unlock(&MyMutex))");
 - 
 - void ProductionGateway::produce() {                                             // To produce in POSIX
 -     ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex));                        // Lock our mutex.
 -     ++Product;                                                                  // Add an item to our product count.
 -     if(Signaled < Waiting) {                                                    // If anybody is waiting that has not
 -         ThreadingCheck19(0 == pthread_cond_signal(&MyConditionVariable));       // yet been signaled then signal them
 -         ++Signaled;                                                             // and keep track. They will count this
 -     }                                                                           // down as they awaken.
 -     ThreadingCheck20(0 == pthread_mutex_unlock(&MyMutex));                      // At the end unlock our mutex so
 - }                                                                               // waiting threads can fly free :-)
 - 
 - const RuntimeCheck ThreadingCheck21("ProductionGateway::consume():ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex))");
 - const RuntimeCheck ThreadingCheck22("ProductionGateway::consume():ThreadingCheck22(0 == pthread_cond_wait(&MyConditionVariable, &MyMutex))");
 - const RuntimeCheck ThreadingCheck23("ProductionGateway::consume():ThreadingCheck23(0 == pthread_mutex_unlock(&MyMutex))");
 - 
 - void ProductionGateway::consume() {                                                 // To consume in POSIX
 -     ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex));                            // Lock our mutex.
 -     while(0 >= Product) {                                                           // Until we have something to consume,
 -         ++Waiting;                                                                  // wait for a signal from
 -         ThreadingCheck22(0 == pthread_cond_wait(&MyConditionVariable, &MyMutex));   // our producer. When we have a signal
 -         --Waiting;                                                                  // we are done waiting and we have
 -         --Signaled;                                                                 // been signaled. Of course, somebody
 -     }                                                                               // may have beaten us to it so check.
 -     --Product;                                                                      // If we have product then take it.
 -     ThreadingCheck23(0 == pthread_mutex_unlock(&MyMutex));                          // At the end unlock our mutex so
 - }
 - 
 - #endif
 - 
 - // End Production Gateway
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - } // End namespace codedweller
 
 
  |