Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phRWLockTest.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011  ---------------------------------------------------------------------------*/
00012 #include <phRWLockTest.h>
00013 #include <phission.h>
00014 #include <time.h>
00015 
00016 /* ------------------------------------------------------------------------ */
00017 int glbl_disable_displays = 0;
00018 
00019 /* ------------------------------------------------------------------------ */
00020 /* phRWLockThread : Test the normal successful operation of a phThread    */
00021 /* ------------------------------------------------------------------------ */
00022 class phRWLockThread : public phThread
00023 {
00024 private:
00025     phRWLock    *m_external_rwlock;
00026     
00027     int run();
00028     int setup();
00029     int wakeup();
00030     int cleanup();
00031     int error();
00032     
00033 public:
00034     phRWLockThread();
00035     ~phRWLockThread();
00036 
00037     phSemaphore *m_sem;
00038     void set( phRWLock *rwlock );
00039 };
00040 
00041 /* ------------------------------------------------------------------------ */
00042 phRWLockThread::phRWLockThread()
00043 {
00044     phFUNCTION("phRWLockThread::phRWLockThread")
00045     this->setName("phRWLockThread");
00046     this->m_sem = new phSemaphore(0,1);
00047     phPROGRESS("\n");
00048 }
00049 
00050 /* ------------------------------------------------------------------------ */
00051 phRWLockThread::~phRWLockThread()
00052 {
00053     phFUNCTION("phRWLockThread::~phRWLockThread")
00054     phPROGRESS("\n");
00055 }
00056 
00057 /* ------------------------------------------------------------------------ */
00058 int phRWLockThread::run()
00059 {
00060     phFUNCTION("phRWLockThread::run")
00061     int nlocks = 0;
00062 
00063     phPROGRESS("calling signal_running() %p\n",this);
00064     
00065     /* Signal the spawning thread that we've woken up */
00066     rc = this->signal_running();
00067     phPRINT_RC(rc,NULL,"this->signal_error");
00068    
00069     while (this->isRunning())
00070     {
00071         /* Wait till we're allowed to try for the rwlock */
00072         phPROGRESS("this->m_sem->take()\n");
00073         rc = this->m_sem->take();
00074         phPRINT_RC(rc,NULL,"this->m_sem->take() failed.");
00075   
00076         /* check to make sure we're still running. If we woke up and isRunning()
00077          * is false then 'wakeup' was called and we should return */
00078         if (!this->isRunning()) continue;
00079         
00080         /* Try for the read lock */
00081         phPROGRESS("rc = this->m_external_rwlock->readLock()\n");
00082         rc = this->m_external_rwlock->readLock();
00083         phPRINT_RC(rc,NULL,"this->m_extenral_rwlock->readLock()");
00084 
00085         /* Print some information */
00086         phPRINT("(%d) Have read lock #%d\n",
00087                 phGetCurrentThreadId(),
00088                 nlocks );
00089 
00090         /* Count the number of loops we get the lock */
00091         nlocks++;
00092 
00093         /* Sleep for a while */
00094         phUSleep(100);
00095 
00096         /* Release the lock */
00097         phPROGRESS("rc = this->m_external_rwlock->rwUnlock()\n");
00098         rc = this->m_external_rwlock->rwUnlock();
00099         phPRINT_RC(rc,NULL,"this->m_external_rwlock->rwUnlock()");
00100     }
00101     
00102     phPROGRESS("returning\n");
00103     return phSUCCESS;
00104 #if 0
00105 error:
00106     phPROGRESS("\n");
00107 
00108     rc = this->signal_error();
00109     phPRINT_RC(rc,NULL,"this->signal_error");
00110     
00111     return phFAIL;
00112 #endif
00113 }
00114 
00115 /* ------------------------------------------------------------------------ */
00116 int phRWLockThread::setup()
00117 {
00118     return phSUCCESS;
00119 }
00120 
00121 /* ------------------------------------------------------------------------ */
00122 int phRWLockThread::wakeup()
00123 {
00124     /* The thread is likely waiting on the semaphore, so post to it. It's the
00125      * thread's responsibility to check to make sure it's still running when it
00126      * wakes up */
00127     this->m_sem->post();
00128     return phSUCCESS;
00129 }
00130 
00131 /* ------------------------------------------------------------------------ */
00132 int phRWLockThread::cleanup()
00133 {
00134     return phSUCCESS;
00135 }
00136 
00137 /* ------------------------------------------------------------------------ */
00138 int phRWLockThread::error()
00139 {
00140     return phSUCCESS;
00141 }
00142 
00143 /* ------------------------------------------------------------------------ */
00144 void phRWLockThread::set( phRWLock *rwlock )
00145 {
00146     this->m_external_rwlock = rwlock;
00147     
00148     return;
00149 }
00150 
00151 /* ------------------------------------------------------------------------ */
00152 int phRWLock_test()
00153 {
00154     phFUNCTION("phRWLock_test")
00155     
00156     phRWLock *lock = new phRWLock();
00157 
00158     /* -------------------------------------------------------------------- */
00159     /* Step 5: Test read/write lock between actual threads */
00160     /* -------------------------------------------------------------------- */
00161 #define SLEEP_TIME 1000 /* us */
00162     /* We're going to allocate 'num_threads' threads to test the
00163      * read-write locks and contention between threads */
00164     const int       num_threads         = 7;
00165     const int       write_lock_count    = 10;
00166     phSystem       *system              = NULL;
00167     phRWLockThread *threads             = NULL;
00168     int             testid              = 0;
00169     int             i                   = 0;
00170     int             j                   = 0;
00171     int             nlocks              = 0;
00172     /* -------------------------------------------------------------------- */
00173 
00174     phPROGRESS("\n");
00175 #if 0
00176     phPROGRESS("--------------------------------------------------\n");
00177     phPROGRESS("1.) 2 x Write Locks: recursive\n");
00178     
00179     phPROGRESS("rc = lock->writeLock()\n");
00180     rc = lock->writeLock();
00181     phPRINT_RC(rc,NULL,"lock->writeLock()");
00182 
00183     phPROGRESS("rc = lock->writeLock()\n");
00184     rc = lock->writeLock();
00185     phPRINT_RC(rc,NULL,"lock->writeLock()");
00186 
00187     phPROGRESS("rc = lock->rwUnlock()\n");
00188     rc = lock->rwUnlock();
00189     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00190 
00191     phPROGRESS("rc = lock->rwUnlock()\n");
00192     rc = lock->rwUnlock();
00193     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00194    
00195     /* ----------------------------------------------------------------------*/
00196     phPROGRESS("--------------------------------------------------\n");
00197     phPROGRESS("2.) Write Lock | Read Lock\n");
00198     
00199     phPROGRESS("rc = lock->writeLock()\n");
00200     rc = lock->writeLock();
00201     phPRINT_RC(rc,NULL,"lock->writeLock()");
00202 
00203     phPROGRESS("rc = lock->readLock()\n");
00204     rc = lock->readLock();
00205     phPRINT_RC(rc,NULL,"lock->readLock()");
00206 
00207     phPROGRESS("rc = lock->rwUnlock()\n");
00208     rc = lock->rwUnlock();
00209     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00210 
00211     phPROGRESS("rc = lock->rwUnlock()\n");
00212     rc = lock->rwUnlock();
00213     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00214     
00215     /* ----------------------------------------------------------------------*/
00216     phPROGRESS("--------------------------------------------------\n");
00217     phPROGRESS("3.) 2 x Read Locks \n");
00218     
00219     phPROGRESS("rc = lock->readLock()\n");
00220     rc = lock->readLock();
00221     phPRINT_RC(rc,NULL,"lock->readLock()");
00222 
00223     phPROGRESS("rc = lock->readLock()\n");
00224     rc = lock->readLock();
00225     phPRINT_RC(rc,NULL,"lock->readLock()");
00226 
00227     phPROGRESS("rc = lock->rwUnlock()\n");
00228     rc = lock->rwUnlock();
00229     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00230 
00231     phPROGRESS("rc = lock->rwUnlock()\n");
00232     rc = lock->rwUnlock();
00233     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00234     
00235     
00236     /* ----------------------------------------------------------------------*/
00237     phPROGRESS("--------------------------------------------------\n");
00238     phPROGRESS("4.) Read Lock | Try Write Lock\n");
00239 
00240     /* timeouts were removed because they aren't supported by pthreads */
00241 #if 0
00242     lock->setTimeoutNS(100000000);
00243     lock->enableTimeout();
00244 #endif
00245     phPROGRESS("rc = lock->readLock()\n");
00246     rc = lock->readLock();
00247     phPRINT_RC(rc,NULL,"lock->readLock()");
00248 
00249     phPROGRESS("rc = lock->tryWriteLock()\n");
00250     rc = lock->tryWriteLock();
00251     phPRINT_RC(rc,NULL,"lock->tryWriteLock()");
00252 
00253     /* Check to see if tryWriteLock succeeded */
00254     if (rc == 0)
00255     {
00256         phPROGRESS("rc = lock->rwUnlock()\n");
00257         rc = lock->rwUnlock();
00258         phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00259     }
00260     else
00261     {
00262         phPROGRESS("SUCCESS: Failure to get lock with tryWriteLock\n");
00263     }
00264 
00265     phPROGRESS("rc = lock->rwUnlock()\n");
00266     rc = lock->rwUnlock();
00267     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00268     
00269     /* timeouts were removed because they aren't supported by pthreads */
00270 #if 0
00271     /* ----------------------------------------------------------------------*/
00272     phPROGRESS("--------------------------------------------------\n");
00273     phPROGRESS("5a.) Read Lock | Timed Write Lock (1*10^9ns)\n");
00274    
00275     lock->setTimeoutNS(100000000);
00276     lock->enableTimeout();
00277     
00278     phPROGRESS("rc = lock->readLock()\n");
00279     rc = lock->readLock();
00280     phPRINT_RC(rc,NULL,"lock->readLock()");
00281 
00282     phPROGRESS("*** NOTE: This will deadlock! ***\n");
00283     
00284     phPROGRESS("rc = lock->writeLock()\n");
00285     rc = lock->writeLock();
00286     phPRINT_RC(rc,NULL,"lock->writeLock()");
00287 
00288     phPROGRESS("rc = lock->rwUnlock()\n");
00289     rc = lock->rwUnlock();
00290     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00291 
00292     phPROGRESS("rc = lock->rwUnlock()\n");
00293     rc = lock->rwUnlock();
00294     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00295     
00296     /* ----------------------------------------------------------------------*/
00297     phPROGRESS("--------------------------------------------------\n");
00298     phPROGRESS("5b.) Read Lock | Timed Write Lock (2*10^9ns)\n");
00299     struct timespec t;
00300     t.tv_sec = 10;
00301     t.tv_nsec = 2000000000;
00302     lock->setTimeoutTimeSpec(t);
00303     lock->enableTimeout();
00304     
00305     phPROGRESS("rc = lock->readLock()\n");
00306     rc = lock->readLock();
00307     phPRINT_RC(rc,NULL,"lock->readLock()");
00308 
00309     phPROGRESS("rc = lock->writeLock()\n");
00310     rc = lock->writeLock();
00311     phPRINT_RC(rc,NULL,"lock->writeLock()");
00312 
00313     phPROGRESS("rc = lock->rwUnlock()\n");
00314     rc = lock->rwUnlock();
00315     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00316 
00317     phPROGRESS("rc = lock->rwUnlock()\n");
00318     rc = lock->rwUnlock();
00319     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00320     
00321     /* ----------------------------------------------------------------------*/
00322     phPROGRESS("--------------------------------------------------\n");
00323     phPROGRESS("5c.) Read Lock | Timed Write Lock (5s)\n");
00324     t.tv_sec = 5;
00325     t.tv_nsec = 0;
00326     lock->setTimeoutTimeSpec(t);
00327     lock->enableTimeout();
00328     
00329     phPROGRESS("rc = lock->readLock()\n");
00330     rc = lock->readLock();
00331     phPRINT_RC(rc,NULL,"lock->readLock()");
00332 
00333     phPROGRESS("rc = lock->writeLock()\n");
00334     rc = lock->writeLock();
00335     phPRINT_RC(rc,NULL,"lock->writeLock()");
00336 
00337     phPROGRESS("rc = lock->rwUnlock()\n");
00338     rc = lock->rwUnlock();
00339     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00340 
00341     phPROGRESS("rc = lock->rwUnlock()\n");
00342     rc = lock->rwUnlock();
00343     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00344 #endif
00345 #endif /* skipping tests, remove this */
00346 
00347     /* ----------------------------------------------------------------------*/
00348     phPROGRESS("--------------------------------------------------\n");
00349     phPROGRESS("5.) Read/Write locking between threads\n");
00350 
00351     threads = new phRWLockThread[num_threads];
00352     phPRINT_PTR(threads,"new",
00353                 "new failed to allocate %d phThreads",num_threads);
00354 
00355     system = new phSystem();
00356     phPRINT_PTR(system,"new","new failed to allocate phSystem");
00357     
00358     for (i = 0; i < num_threads; i++ )
00359     {
00360         rc = system->add(&(threads[i]));
00361         phPRINT_RC(rc,NULL,"system->add(threads[%d]) failed",i);
00362 
00363         threads[i].set(lock);
00364     }
00365     
00366     /* Start the system of read locking threads */
00367     phPROGRESS("rc = system.startup()\n");
00368     rc = system->startup();
00369     phPRINT_RC(rc,NULL,"rc = system.startup()");
00370     
00371     for (i = 0; i < write_lock_count; i++ )
00372     {
00373         /* wait for the readers to get started with the read lock */
00374         /* A problem exists between rwUnlock and writelock that can cause
00375          * starvation of the readers in our implementation. If the rwUnlock
00376          * and writelock happen in the same timeslice, waiting readers will
00377          * not get through. Simple yielding may not work. If the write
00378          * thread has higher priorty, then it could signal the readers but
00379          * get the lock again before any reader can get through. 
00380          *  The assumption is that the write thread will take some amount of
00381          * time between it's rwUnlock and it's writeLock to acquire new data.
00382          * This is simulated with a lengthy sleep */
00383         if (i > 0) 
00384         {
00385             phPROGRESS("phUSleep(2000);\n");
00386             phUSleep(2000);
00387         }
00388 
00389         /* Try to get the write lock */
00390         phPROGRESS("rc = lock->writeLock()\n");
00391         rc = lock->writeLock();
00392         phPRINT_RC(rc,NULL,"rc = lock->writeLock()");
00393 
00394         phPRINT("(%d) Have write lock #%d\n",
00395                 phGetCurrentThreadId(),  nlocks );
00396 
00397         nlocks++;
00398 
00399         /* Let the reader threads go */
00400         for (j = 0; j < num_threads; j++ )
00401         {
00402             phPROGRESS("rc = threads[j].sem->post()\n");
00403             rc = threads[j].m_sem->post();
00404             phPRINT_RC(rc,NULL,"rc = threads[j].sem->post()");
00405         }
00406 
00407         /* wait a little bit - give the other processes time to wake up and wait
00408          * on the reader lock */
00409         /* This could simulate the writing of a large amount of data that causes
00410          * the writing thread to take up more than one timeslice. It allows
00411          * other threads to get through and try the read lock */
00412         phPROGRESS("phUSleep(2000);\n");
00413         phUSleep(2000);
00414 
00415         /* release the lock */
00416         phPROGRESS("rc = lock->rwUnlock()\n");
00417         rc = lock->rwUnlock();
00418         phPRINT_RC(rc,NULL,"rc = lock->rwUnlock()");
00419     }
00420 
00421     /* stop the threads */
00422     for (i = 0; i < num_threads; i++ )
00423     {
00424         phPROGRESS("rc = system->shutdown()\n");
00425         rc = system->shutdown();
00426         phPRINT_RC(rc,NULL,"rc = system->shutdown()");
00427     }
00428 
00429     /* Delete the array of threads and the system */
00430     phDeleteArray(threads);
00431     phDelete(system);
00432     
00433     /* ----------------------------------------------------------------------*/
00434     phPROGRESS("--------------------------------------------------\n");
00435     phPROGRESS("6.) Read Lock | Write Lock\n");
00436    
00437     /* timeouts were removed because they aren't supported by pthreads */
00438 #if 0
00439     lock->disableTimeout();
00440 #endif
00441     
00442     phPROGRESS("rc = lock->readLock()\n");
00443     rc = lock->readLock();
00444     phPRINT_RC(rc,NULL,"lock->readLock()");
00445 
00446     phPROGRESS("rc = lock->writeLock() - we should never get through\n");
00447     rc = lock->writeLock();
00448     phPRINT_RC(rc,NULL,"lock->writeLock()");
00449 
00450     phPROGRESS("rc = lock->rwUnlock()\n");
00451     rc = lock->rwUnlock();
00452     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00453 
00454     phPROGRESS("rc = lock->rwUnlock()\n");
00455     rc = lock->rwUnlock();
00456     phPRINT_RC(rc,NULL,"lock->rwUnlock()");
00457     
00458 
00459     /* ----------------------------------------------------------------------*/
00460     phPROGRESS("--------------------------------------------------\n");
00461     phPROGRESS("phDelete(lock)\n");
00462     phDelete(lock);
00463     
00464     return phSUCCESS;
00465 }
00466     
00467 /* ------------------------------------------------------------------------ */
00468 /* ------------------------------------------------------------------------ */
00469 int main(int argc, char *argv[] )
00470 {
00471     phFUNCTION("main")
00472 
00473     rc = phRWLock_test();
00474 error:
00475 
00476     return phSUCCESS;
00477 }




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:07 2007 for phission by  doxygen 1.4.4