// ------------------------------- // // -------- Start of File -------- // // ------------------------------- // // ----------------------------------------------------------- // // C++ Source Code File Name: testprog.cpp // Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC // Produced By: glNET Software // File Creation Date: 03/25/2000 // Date Last Modified: 07/23/2001 // Copyright (c) 2001 glNET Software // ----------------------------------------------------------- // // ------------- Program Description and Details ------------- // // ----------------------------------------------------------- // /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Test program demonstrating the basic operation of the gxThread class using mutex and condition variable synchronization primitives. */ // ----------------------------------------------------------- // #include <iostream.h> #include "gxthread.h" #include "gxmutex.h" #include "gxcond.h" #ifdef __MSVC_DEBUG__ #include "leaktest.h" #endif // Constants const int NUMTHREADS = 2; // Global synchronization objects gxMutex dataMutex; gxCondition dataPresentCondition; // Global variables int dataPresent = 0; int sharedData = 0; class ConsumerThread : public gxThread { private: // Base class interface void *ThreadEntryRoutine(gxThread_t *thread); }; void *ConsumerThread::ThreadEntryRoutine(gxThread_t *thread) // Thread's entry function { int retries = 1; cout << "Entering consumer thread" << "\n"; if(dataMutex.MutexLock() != 0) { cout << "Consumer thread mutex lock failed!" << "\n"; cout << dataMutex.MutexExceptionMessage() << "\n"; 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" << "\n"; if(dataPresentCondition.ConditionWait(&dataMutex) != 0) { cout << "Consumer thread condition wait failed!" << "\n"; cout << dataPresentCondition.ConditionExceptionMessage() << "\n"; dataMutex.MutexUnlock(); return ExitThread(thread, 1); } } cout << "Consumer thread found data or notified" << "\n"; cout << "CONSUME DATA while holding lock" << "\n"; // 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 gxCondition::ConditionWait() function releases it atomically } cout << "Consumer thread done" << "\n"; if(dataMutex.MutexUnlock() != 0) { cout << "Consumer thread mutex unlock failed!" << "\n"; cout << dataMutex.MutexExceptionMessage() << "\n"; return ExitThread(thread, 1); } return 0; } // Program's main thread of execution int main() { #ifdef __MSVC_DEBUG__ InitLeakTest(); #endif ConsumerThread t; gxThread_t *thread[NUMTHREADS]; int amountOfData = 4; int i; cout << "Create/start threads" << "\n"; for(i = 0; i < NUMTHREADS; ++i) { thread[i] = t.CreateThread(); if(thread[i]->GetThreadError() != gxTHREAD_NO_ERROR) cout << thread[i]->ThreadExceptionMessage() << "\n"; } // The producer loop while(amountOfData--) { cout << "Producer finding data..." << "\n"; t.sSleep(1); if(dataMutex.MutexLock() != 0) { // Protect shared data and flag cout << "Producer thread mutex lock failed!" << "\n"; cout << dataMutex.MutexExceptionMessage() << "\n"; } cout << "Producer thread make data shared and notify consumer" << "\n"; ++sharedData; // Add data dataPresent = 1; // Set boolean predicate // Wake up a consumer if(dataPresentCondition.ConditionSignal() != 0) { cout << "Producer thread condition signal failed!" << "\n"; cout << dataPresentCondition.ConditionExceptionMessage() << "\n"; dataMutex.MutexUnlock(); return 1; } cout << "Producer thread unlock shared data and flag" << "\n"; if(dataMutex.MutexUnlock() != 0) { cout << "Producer thread mutex unlock failed!" << "\n"; cout << dataMutex.MutexExceptionMessage() << "\n"; } } cout << "Wait for the threads to complete, and release their resources" << "\n"; for(i = 0; i < NUMTHREADS; i++) { if(t.JoinThread(thread[i]) != 0) cout << "Could not join the thread" << "\n"; if(thread[i]->GetThreadExitCode() != 0) cout << "This thread exited with an error" << "\n"; } // Release any memory the thread is still holding for(i = 0; i < NUMTHREADS; i++) { if(t.DestroyThread(thread[i]) != 0) { cout << "Error destroying thread!" << "\n"; } } return 0; } // ----------------------------------------------------------- // // ------------------------------- // // --------- End of File --------- // // ------------------------------- //