|
|
@@ -59,13 +59,13 @@ bool ThreadManager::lockExistingThread(Thread* T) { |
|
|
|
LockedThread = T; // set our locked thread and |
|
|
|
return true; // return true; |
|
|
|
} |
|
|
|
|
|
|
|
// We use assert() in the code below because if these conditions fail then there |
|
|
|
// is something seriously wrong and potentially dangerous with the calling code. |
|
|
|
|
|
|
|
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. |
|
|
|
assert(0 != LockedThread); // We had better have a locked thread. |
|
|
|
assert(T == LockedThread); // The locked thread had better match. |
|
|
|
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. |
|
|
|
} |
|
|
@@ -272,15 +272,19 @@ void Thread::join() { |
|
|
|
// 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 |
|
|
|
assert(NULL != MyMutex); // a count of 1. |
|
|
|
ThreadingCheck3(NULL != MyMutex); // a count of 1. |
|
|
|
} |
|
|
|
|
|
|
|
const ExitCheck ThreadingCheck4("Mutex::~Mutex():");
|
|
|
|
|
|
|
|
Mutex::~Mutex() { // Destroying a WIN32 Mutex means |
|
|
|
assert(false == IAmLocked); // Make sure we're not in use and |
|
|
|
ThreadingCheck4(false == IAmLocked); // Make sure we're not in use and |
|
|
|
CloseHandle(MyMutex); // destroy the semaphore object. |
|
|
|
} |
|
|
|
|
|
|
@@ -295,14 +299,18 @@ bool Mutex::tryLock() { |
|
|
|
} |
|
|
|
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 |
|
|
|
assert(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE)); // Wait on the semaphore - only 1 will |
|
|
|
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 |
|
|
|
assert(true == IAmLocked); // making sure we're really locked then |
|
|
|
ThreadingCheck6(true == IAmLocked); // making sure we're really locked then |
|
|
|
IAmLocked = false; // reset the IAmLocked flag and |
|
|
|
ReleaseSemaphore(MyMutex, 1, NULL); // release the semaphore. |
|
|
|
} |
|
|
@@ -312,26 +320,36 @@ bool Mutex::isLocked() { return IAmLocked; } |
|
|
|
#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 |
|
|
|
assert(0 == pthread_mutex_init(&MyMutex,NULL)); // initializing the mutex_t object. |
|
|
|
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 |
|
|
|
assert(false == IAmLocked); // to see that it is not locked and |
|
|
|
assert(0 == pthread_mutex_destroy(&MyMutex)); // destroy the primative. |
|
|
|
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 |
|
|
|
assert(0 == pthread_mutex_lock(&MyMutex)); // asserting our lock was successful and |
|
|
|
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 |
|
|
|
assert(true == IAmLocked); // asserting that we are locked, |
|
|
|
IAmLocked = false; // clearing the IAmLocked flag. |
|
|
|
assert(0 == pthread_mutex_unlock(&MyMutex)); // asserting our unlock was successful and |
|
|
|
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 |
|
|
@@ -372,11 +390,13 @@ ScopeMutex::~ScopeMutex() { |
|
|
|
#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. |
|
|
|
assert(NULL != MySemaphore); // That should always work. |
|
|
|
ThreadingCheck13(NULL != MySemaphore); // That should always work. |
|
|
|
} |
|
|
|
|
|
|
|
ProductionGateway::~ProductionGateway() { // Be sure to close it when we're done. |
|
|
@@ -394,40 +414,54 @@ void ProductionGateway::consume() { |
|
|
|
#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) { |
|
|
|
assert(0 == pthread_mutex_init(&MyMutex, NULL)); // Initialize our mutex. |
|
|
|
assert(0 == pthread_cond_init(&MyConditionVariable, NULL)); // Initialize our condition variable. |
|
|
|
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 |
|
|
|
assert(0 == pthread_mutex_destroy(&MyMutex)); // our local mutex and |
|
|
|
assert(0 == pthread_cond_destroy(&MyConditionVariable)); // our condition variable. |
|
|
|
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 |
|
|
|
assert(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |
|
|
|
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 |
|
|
|
assert(0 == pthread_cond_signal(&MyConditionVariable)); // yet been signaled then signal them |
|
|
|
ThreadingCheck19(0 == pthread_cond_signal(&MyConditionVariable)); // yet been signaled then signal them |
|
|
|
++Signaled; // and keep track. They will count this |
|
|
|
} // down as they awaken. |
|
|
|
assert(0 == pthread_mutex_unlock(&MyMutex)); // At the end unlock our mutex so |
|
|
|
ThreadingCheck20(0 == pthread_mutex_unlock(&MyMutex)); // At the end unlock our mutex so |
|
|
|
} // waiting threads can fly free :-) |
|
|
|
|
|
|
|
void ProductionGateway::consume() { // To consume in POSIX |
|
|
|
assert(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |
|
|
|
while(0 >= Product) { // Until we have something to consume, |
|
|
|
++Waiting; // wait for a signal from |
|
|
|
assert(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. |
|
|
|
assert(0 == pthread_mutex_unlock(&MyMutex)); // At the end unlock our mutex so |
|
|
|
|
|
|
|
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 |