00001 /* **************************************************************************** 00002 * Owner: Evgeniy Makeev 00003 * Created by: Evgeniy Makeev 00004 * **************************************************************************** 00005 */ 00006 #ifndef __EVG_RW_LOCK_2_H_Included__ 00007 #define __EVG_RW_LOCK_2_H_Included__ 00008 00009 #include "atomic_util.h" 00010 #include "system_abstraction.h" 00011 00012 /*---------------------------------*/ 00013 /* Written by Evgeniy Makeev, 2005 */ 00014 /*---------------------------------*/ 00015 // 00016 // Multiple readers - one writer interface class. 00017 // Implements multiple readers one writer mechanism. 00018 // Optimizes readers speed, provides fast readers 00019 // synchronization when no writers are waiting. 00020 // Useful when data is needed to be written/changed 00021 // only occasionally but it is read often by multiple 00022 // threads. 00023 // 00024 00025 class EvgRWLock2 00026 { 00027 volatile int readers; 00028 // 00029 // Can be overwritten with a system specific yield thread 00030 // or sleep implementation 00031 // 00032 inline void yield() 00033 { 00034 thread_yield(); 00035 } 00036 00037 public: 00038 static const char *name() { return "Evgeniy's RW Lock 2"; } 00039 00040 EvgRWLock2() : rwdata(0L) {} 00041 // 00042 // Must be called at the beginning of any read/data access. 00043 // 00044 inline void enter_read(void) 00045 { 00046 if(atomic_inc_return(&rwdata) & 0xFFFF8000) 00047 for(;;) 00048 { 00049 if(atomic_dec_return(&rwdata) & 0xFFFF8000) yield(); 00050 if((atomic_inc_return(&rwdata) & 0xFFFF8000)==0) break; 00051 } 00052 } 00053 // 00054 // Must be called at the end of any read/data access. 00055 // 00056 inline void leave_read(void) 00057 { 00058 atomic_dec(&rwdata); 00059 } 00060 // 00061 // Must be called at the beginning of a write operation 00062 // 00063 inline void enter_write(void) 00064 { 00065 if(atomic_cmpexch_return(&rwdata, 0x00008000, 0)) 00066 { 00067 atomic_add(&rwdata, 0x00010000); 00068 for(;;) 00069 { 00070 if(atomic_cmpexch_return_w((short *)&rwdata, (short)0x8000, (short)0) == 0) 00071 { 00072 atomic_add(&rwdata, -0x00010000); 00073 break; 00074 } 00075 yield(); 00076 } 00077 } 00078 } 00079 // 00080 // Must be called at the end of a write operation 00081 // 00082 inline void leave_write(void) 00083 { 00084 atomic_and(&rwdata, ~0x00008000); 00085 } 00086 }; 00087 00088 #endif // __EVG_RW_LOCK_2_H_Included__ 00089 00090 00091
1.5.5