// ------------------------------- // // -------- Start of File -------- // // ------------------------------- // // ----------------------------------------------------------- // // C++ Source Code File Name: testprog.cpp // Compiler Used: MSVC40, egcs-2.90.29, HP CPP 10.24 // Produced By: Doug Gaer // File Creation Date: 03/25/2000 // Date Last Modified: 05/26/2000 // Copyright (c) 2000 Douglas M. Gaer // ----------------------------------------------------------- // // ------------- Program Description and Details ------------- // // ----------------------------------------------------------- // /* The VBD and VBS C++ classes are copyright (c) 1997 and 2000 by Douglas M. Gaer. All those who put this code or its derivatives in a commercial product MUST mention this copyright in their documentation for users of the products in which this code or its derivative classes are used. Otherwise, you have the freedom to redistribute verbatim copies of this source code, adapt it to your specific needs, or improve the code and release your improvements to the public provided that the modified files carry prominent notices stating that you changed the files and the date of any change. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE, YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. Test program demonstrating the basic operation of the vbThread class using mutex and condition variable synchronization primitives. */ // ----------------------------------------------------------- // #include <iostream.h> #include "vbthread.h" #include "vbmutex.h" #include "vbcond.h" // Constants const int NUMTHREADS = 2; // Global synchronization objects vbMutex dataMutex; vbCondition dataPresentCondition; // Global variables int dataPresent = 0; int sharedData = 0; class ConsumerThread : public vbThread { private: // Base class interface void *ThreadEntryRoutine(vbThread_t *thread); }; void *ConsumerThread::ThreadEntryRoutine(vbThread_t *thread) // Thread's entry function { int retries=2; cout << "Entering consumer thread" << endl; if(dataMutex.MutexLock() != 0) { cout << "Consumer thread mutex lock failed!" << endl; cout << dataMutex.MutexExceptionMessage() << endl; return ExitThread(thread, 1); } while(retries--) { // The boolean dataPresent value is required for safe use of // condition variables. If no data is present we wait, other // wise we process immediately. while(!dataPresent) { cout << "Consumer thread waiting for data to be produced" << endl; if(dataPresentCondition.ConditionWait(&dataMutex) != 0) { cout << "Consumer thread condition wait failed!" << endl; cout << dataPresentCondition.ConditionExceptionMessage() << endl; dataMutex.MutexUnlock(); return ExitThread(thread, 1); } } cout << "Consumer thread found data or notified" << endl; cout << "CONSUME DATA while holding lock" << endl; // Typically an application should remove the data from being // in the shared structure or Queue, then unlock. Processing // of the data does not necessarily require that the lock is held // Access to shared data goes here --sharedData; // We consumed the last of the data if(sharedData == 0) dataPresent=0; // Repeat holding the lock. // The vbCondition::ConditionWait() function releases it atomically } cout << "Consumer thread done" << endl; if(dataMutex.MutexUnlock() != 0) { cout << "Consumer thread mutex unlock failed!" << endl; cout << dataMutex.MutexExceptionMessage() << endl; return ExitThread(thread, 1); } return 0; } // Program's main thread of execution int main() { ConsumerThread t; vbThread_t *thread[NUMTHREADS]; int amountOfData = 4; int i; cout << "Create/start threads" << endl; for(i = 0; i < NUMTHREADS; ++i) { thread[i] = t.CreateThread(); if(thread[i]->GetThreadError() != vbTHREAD_NO_ERROR) cout << thread[i]->ThreadExceptionMessage() << endl; } // The producer loop while(amountOfData--) { cout << "Producer finding data..." << endl; t.sSleep(1); if(dataMutex.MutexLock() != 0) { // Protect shared data and flag cout << "Producer thread mutex lock failed!" << endl; cout << dataMutex.MutexExceptionMessage() << endl; } cout << "Producer thread make data shared and notify consumer" << endl; ++sharedData; // Add data dataPresent = 1; // Set boolean predicate // Wake up a consumer if(dataPresentCondition.ConditionSignal() != 0) { cout << "Producer thread condition signal failed!" << endl; cout << dataPresentCondition.ConditionExceptionMessage() << endl; dataMutex.MutexUnlock(); return 1; } cout << "Producer thread unlock shared data and flag" << endl; if(dataMutex.MutexUnlock() != 0) { cout << "Producer thread mutex unlock failed!" << endl; cout << dataMutex.MutexExceptionMessage() << endl; } } cout << "Wait for the threads to complete, and release their resources" << endl; for(i = 0; i < NUMTHREADS; i++) { if(t.JoinThread(thread[i]) != 0) cout << "Could not join the thread" << endl; if(thread[i]->GetThreadExitCode() != 0) cout << "This thread exited with an error" << endl; } return 0; } // ----------------------------------------------------------- // // ------------------------------- // // --------- End of File --------- // // ------------------------------- //