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 |