// ------------------------------- // // -------- 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: 05/17/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. This is a test program used demonstrate the use of the VBD file manager in a multi-threaded application. */ // ----------------------------------------------------------- // #include <iostream.h> #include <string.h> #include "vbthread.h" #include "vbmutex.h" #include "vbcond.h" #include "vbdfile.h" // Constants const int NUM_THREADS = 26; const int name_length = 16; const char *name_string = "File Object "; struct FileObject { char name[name_length]; int id; }; // Class used to perform multi-threaded reads class vbdReadThread : public vbThread { public: vbdReadThread(VBDFilePtr vbdfile) { f = vbdfile; curr_offset = (FAU)0; } ~vbdReadThread() { } private: // Base class interface void *ThreadEntryRoutine(vbThread_t *thread); private: VBDFilePtr f; // Pointer to the open database file vbMutex offset_lock; // Mutex used to serialize access to curr_offset FAU curr_offset; // Current file position following a file read }; // Class used to perform multi-threaded writes class vbdWriteThread : public vbThread { public: vbdWriteThread(VBDFilePtr vbdfile) { f = vbdfile; is_locked = 0; } ~vbdWriteThread() { } private: // Base class interface void *ThreadEntryRoutine(vbThread_t *thread); private: vbMutex write_lock; // Mutex object used to lock the file vbCondition write_cond; // Condition variable used to block other threads int is_locked; // Variable used to indicate that the file is locked VBDFilePtr f; // Pointer to the open database file }; void *vbdReadThread::ThreadEntryRoutine(vbThread_t *thread) { offset_lock.MutexLock(); // Serialize access to curr_offset curr_offset = f->FindFirstObject(curr_offset); if(curr_offset) { FileObject ob; f->Read(&ob, sizeof(FileObject), curr_offset); cout << "Reading: \"" << ob.name << "\" at address: " << (long)curr_offset << "\n" << flush; } offset_lock.MutexUnlock(); return 0; } void *vbdWriteThread::ThreadEntryRoutine(vbThread_t *thread) // Thread safe write function that will not allow access to // the critical section until the write operation is complete. { FileObject *ob = (FileObject *)thread->GetThreadParm(); write_lock.MutexLock(); while(is_locked) { // Block this thread from its own execution if a another thread // is writing to the file write_cond.ConditionWait(&write_lock); } is_locked = 1; // Tell other threads to wait until this write is complete // ********** Enter Critical Section ******************* // f->Alloc(sizeof(FileObject)); f->Write(ob, sizeof(FileObject)); // ********** Leave Critical Section ******************* // is_locked = 0; // Tell other threads that this write is complete // Wake up the next thread waiting on this condition write_cond.ConditionSignal(); write_lock.MutexUnlock(); return 0; } int main() { VBDFilePtr f(new VBDFile); const char *fname = "testfile.vbd"; f->Create(fname); // Open the file and truncate it // Initialize the multi-threaded VBD objects vbdReadThread *read_thread = new vbdReadThread(f); vbdWriteThread *write_thread = new vbdWriteThread(f); // Arrays used to hold the read and write threads vbThread_t *wthreads[NUM_THREADS]; vbThread_t *rthreads[NUM_THREADS]; int i, j; cout << "Writing " << NUM_THREADS << " objects to the " << fname << " file" << endl; for(i = 0; i < NUM_THREADS; i++) { FileObject *ob = new FileObject; // Persistent object ob->id = 65+i; for(j = 0; j < name_length; j++) ob->name[j] = 0; memmove(ob->name, name_string, strlen(name_string)); ob->name[strlen(name_string)] = char(ob->id); wthreads[i] = write_thread->CreateThread((void *)ob); } for(i = 0; i < NUM_THREADS; i++) write_thread->JoinThread(wthreads[i]); cout << "Write complete" << endl; cout << "Verifing each object" << endl; cout << "Press Enter to continue..." << endl; cin.get(); for(i = 0; i < NUM_THREADS; i++) { rthreads[i] = read_thread->CreateThread(); read_thread->sSleep(1); // Allow each thread time to print its message } // Wait for the read threads to complete for(i = 0; i < NUM_THREADS; i++) read_thread->JoinThread(rthreads[i]); // Cleanup and release all the thread resources for(i = 0; i < NUM_THREADS; i++) write_thread->DestroyThread(wthreads[i]); for(i = 0; i < NUM_THREADS; i++) read_thread->DestroyThread(rthreads[i]); delete write_thread; // Release the write object's file pointer delete read_thread; // Release the read object's file pointer f->Close(); // Close the file return 0; } // ----------------------------------------------------------- // // ------------------------------- // // --------- End of File --------- // // ------------------------------- //