|
|
|
|
|
|
|
|
LockedThread = T; // set our locked thread and |
|
|
LockedThread = T; // set our locked thread and |
|
|
return true; // return true; |
|
|
return true; // return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck1("ThreadManager::unlockExistingThread():ThreadingCheck1(0 != LockedThread)");
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck2("ThreadManager::unlockExistingThread():ThreadingCheck2(T == LockedThread)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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. |
|
|
void ThreadManager::unlockExistingThread(Thread* T) { // Unlocks ThreadManager if T locked. |
|
|
ThreadingCheck1(0 != LockedThread); // We had better have a locked thread. |
|
|
ThreadingCheck1(0 != LockedThread); // We had better have a locked thread. |
|
|
|
|
|
|
|
|
Thread::Thread() : // When constructing a WIN32 thread |
|
|
Thread::Thread() : // When constructing a WIN32 thread |
|
|
MyThreadType(Thread::Type), // Use generic Thread Type. |
|
|
MyThreadType(Thread::Type), // Use generic Thread Type. |
|
|
MyThreadName("UnNamed Thread"), // Use a generic Thread Name. |
|
|
MyThreadName("UnNamed Thread"), // Use a generic Thread Name. |
|
|
MyThread(NULL), // Null the thread handle.
|
|
|
|
|
|
|
|
|
MyThread(NULL), // Null the thread handle. |
|
|
RunningFlag(false), // Couldn't be running yet. |
|
|
RunningFlag(false), // Couldn't be running yet. |
|
|
BadFlag(false) { // Couldn't be bad yet. |
|
|
BadFlag(false) { // Couldn't be bad yet. |
|
|
Threads.rememberThread(this); // Remember this thread. |
|
|
Threads.rememberThread(this); // Remember this thread. |
|
|
|
|
|
|
|
|
Thread::Thread(const ThreadType& T, const string N) : // Construct with specific Type/Name |
|
|
Thread::Thread(const ThreadType& T, const string N) : // Construct with specific Type/Name |
|
|
MyThreadType(T), // Use generic Thread Type. |
|
|
MyThreadType(T), // Use generic Thread Type. |
|
|
MyThreadName(N), // Use a generic Thread Name. |
|
|
MyThreadName(N), // Use a generic Thread Name. |
|
|
MyThread(NULL), // Null the thread handle.
|
|
|
|
|
|
|
|
|
MyThread(NULL), // Null the thread handle. |
|
|
RunningFlag(false), // Couldn't be running yet. |
|
|
RunningFlag(false), // Couldn't be running yet. |
|
|
BadFlag(false) { // Couldn't be bad yet. |
|
|
BadFlag(false) { // Couldn't be bad yet. |
|
|
Threads.rememberThread(this); // Remember this thread. |
|
|
Threads.rememberThread(this); // Remember this thread. |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
unsigned __stdcall runThreadTask(void* thread_object) { // The WIN32 version has this form. |
|
|
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.
|
|
|
|
|
|
|
|
|
((Thread*)thread_object)->launchTask(); // Run the task. |
|
|
|
|
|
_endthreadex(0); // Signal the thread is finished. |
|
|
return 0; // Satisfy the unsigned return. |
|
|
return 0; // Satisfy the unsigned return. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* runThreadTask(void* thread_object) { // The POSIX version has this form. |
|
|
void* runThreadTask(void* thread_object) { // The POSIX version has this form. |
|
|
((Thread*)thread_object)->launchTask(); |
|
|
((Thread*)thread_object)->launchTask(); |
|
|
|
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Thread::run() { // Run a POSIX thread... |
|
|
void Thread::run() { // Run a POSIX thread... |
|
|
|
|
|
|
|
|
// additional research it was determined that the use of a Semaphore with an |
|
|
// 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 - |
|
|
// initial count of 1 would work better overall on multiple Winx platforms - |
|
|
// especially SMP systems. |
|
|
// especially SMP systems. |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck3("Mutex::Mutex():ThreadingCheck3(NULL != MyMutex)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck3("Mutex::Mutex():ThreadingCheck3(NULL != MyMutex)"); |
|
|
|
|
|
|
|
|
Mutex::Mutex() : // Creating a WIN32 Mutex means |
|
|
Mutex::Mutex() : // Creating a WIN32 Mutex means |
|
|
IAmLocked(false) { // Setting IAmLocked to false and |
|
|
IAmLocked(false) { // Setting IAmLocked to false and |
|
|
MyMutex = CreateSemaphore(NULL, 1, 1, NULL); // create a semaphore object with |
|
|
MyMutex = CreateSemaphore(NULL, 1, 1, NULL); // create a semaphore object with |
|
|
ThreadingCheck3(NULL != MyMutex); // a count of 1. |
|
|
ThreadingCheck3(NULL != MyMutex); // a count of 1. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const ExitCheck ThreadingCheck4("Mutex::~Mutex():");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ExitCheck ThreadingCheck4("Mutex::~Mutex():"); |
|
|
|
|
|
|
|
|
Mutex::~Mutex() { // Destroying a WIN32 Mutex means |
|
|
Mutex::~Mutex() { // Destroying a WIN32 Mutex means |
|
|
ThreadingCheck4(false == IAmLocked); // Make sure we're not in use and |
|
|
ThreadingCheck4(false == IAmLocked); // Make sure we're not in use and |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
return DoIHaveIt; // Return true if we got it (see above). |
|
|
return DoIHaveIt; // Return true if we got it (see above). |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck5("Mutex::lock():ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck5("Mutex::lock():ThreadingCheck5(WAIT_OBJECT_0 == WaitForSingleObject(MyMutex, INFINITE))"); |
|
|
|
|
|
|
|
|
void Mutex::lock() { // Locking the WIN32 Mutex means |
|
|
void Mutex::lock() { // Locking the WIN32 Mutex means |
|
|
ThreadingCheck5(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. |
|
|
IAmLocked = true; // get through or we have a big problem. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const LogicCheck ThreadingCheck6("Mutex::unlock():ThreadingCheck6(true == IAmLocked)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const LogicCheck ThreadingCheck6("Mutex::unlock():ThreadingCheck6(true == IAmLocked)"); |
|
|
|
|
|
|
|
|
void Mutex::unlock() { // Unlocking the WIN32 Mutex means |
|
|
void Mutex::unlock() { // Unlocking the WIN32 Mutex means |
|
|
ThreadingCheck6(true == IAmLocked); // making sure we're really locked then |
|
|
ThreadingCheck6(true == IAmLocked); // making sure we're really locked then |
|
|
|
|
|
|
|
|
#else |
|
|
#else |
|
|
|
|
|
|
|
|
// POSIX Mutex Implementation ////////////////////////////////////////////////// |
|
|
// POSIX Mutex Implementation ////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck7("Mutex::Mutex():ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck7("Mutex::Mutex():ThreadingCheck7(0 == pthread_mutex_init(&MyMutex,NULL))"); |
|
|
|
|
|
|
|
|
Mutex::Mutex() : // Constructing a POSIX mutex means |
|
|
Mutex::Mutex() : // Constructing a POSIX mutex means |
|
|
IAmLocked(false) { // setting the IAmLocked flag to false and |
|
|
IAmLocked(false) { // setting the IAmLocked flag to false and |
|
|
ThreadingCheck7(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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
Mutex::~Mutex() { // Before we destroy our mutex we check |
|
|
ThreadingCheck8(false == IAmLocked); // to see that it is not locked and |
|
|
ThreadingCheck8(false == IAmLocked); // to see that it is not locked and |
|
|
ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex)); // destroy the primative. |
|
|
ThreadingCheck9(0 == pthread_mutex_destroy(&MyMutex)); // destroy the primative. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck10("Mutex::lock():ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex));");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck10("Mutex::lock():ThreadingCheck10(0 == pthread_mutex_lock(&MyMutex));"); |
|
|
|
|
|
|
|
|
void Mutex::lock() { // Locking a POSIX mutex means |
|
|
void Mutex::lock() { // Locking a POSIX mutex means |
|
|
ThreadingCheck10(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. |
|
|
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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
void Mutex::unlock() { // Unlocking a POSIX mutex means |
|
|
ThreadingCheck11(true == IAmLocked); // asserting that we are locked, |
|
|
ThreadingCheck11(true == IAmLocked); // asserting that we are locked, |
|
|
|
|
|
|
|
|
bool DoIHaveIt = false; // starting off pessimistically. |
|
|
bool DoIHaveIt = false; // starting off pessimistically. |
|
|
if(false == IAmLocked) { // If we are not locked yet then we |
|
|
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 |
|
|
if(0 == pthread_mutex_trylock(&MyMutex)) { // try to lock the mutex. If we succeed |
|
|
DoIHaveIt = IAmLocked = true; // we set our IAmLocked flag and our |
|
|
|
|
|
} // DoIHaveIt flag to true; |
|
|
|
|
|
|
|
|
IAmLocked = true; // we set our IAmLocked flag and our |
|
|
|
|
|
DoIHaveIt = true; // DoIHaveIt flag to true; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
return DoIHaveIt; // In any case we return the result. |
|
|
return DoIHaveIt; // In any case we return the result. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef WIN32 |
|
|
#ifdef WIN32 |
|
|
|
|
|
|
|
|
// Win32 Implementation //////////////////////////////////////////////////////// |
|
|
// Win32 Implementation //////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck13("ProductionGateway::ProductionGateway():ThreadingCheck13(NULL != MySemaphore)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RuntimeCheck ThreadingCheck13("ProductionGateway::ProductionGateway():ThreadingCheck13(NULL != MySemaphore)"); |
|
|
|
|
|
|
|
|
ProductionGateway::ProductionGateway() { // Construct in Windows like this: |
|
|
ProductionGateway::ProductionGateway() { // Construct in Windows like this: |
|
|
const int HUGENUMBER = 0x7fffffL; // Work without any real limits. |
|
|
const int HUGENUMBER = 0x7fffffL; // Work without any real limits. |
|
|
|
|
|
|
|
|
#else |
|
|
#else |
|
|
|
|
|
|
|
|
// POSIX Implementation //////////////////////////////////////////////////////// |
|
|
// 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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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: |
|
|
ProductionGateway::ProductionGateway() : // Construct in POSIX like this: |
|
|
Product(0), // All of our counts start at zero. |
|
|
Product(0), // All of our counts start at zero. |
|
|
|
|
|
|
|
|
ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL)); // Initialize our mutex. |
|
|
ThreadingCheck14(0 == pthread_mutex_init(&MyMutex, NULL)); // Initialize our mutex. |
|
|
ThreadingCheck15(0 == pthread_cond_init(&MyConditionVariable, NULL)); // Initialize our condition variable. |
|
|
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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
ProductionGateway::~ProductionGateway() { // When we're done we must destroy |
|
|
ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex)); // our local mutex and |
|
|
ThreadingCheck16(0 == pthread_mutex_destroy(&MyMutex)); // our local mutex and |
|
|
ThreadingCheck17(0 == pthread_cond_destroy(&MyConditionVariable)); // our condition variable. |
|
|
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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
void ProductionGateway::produce() { // To produce in POSIX |
|
|
ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |
|
|
ThreadingCheck18(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |
|
|
|
|
|
|
|
|
} // down as they awaken. |
|
|
} // down as they awaken. |
|
|
ThreadingCheck20(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 :-) |
|
|
} // 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))");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
void ProductionGateway::consume() { // To consume in POSIX |
|
|
ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |
|
|
ThreadingCheck21(0 == pthread_mutex_lock(&MyMutex)); // Lock our mutex. |