lw_lock.h

Go to the documentation of this file.
00001 00012 // Copyright (C) 1995-2002 Brad Wilson 00013 // 00014 // This material is provided "as is", with absolutely no warranty 00015 // expressed or implied. Any use is at your own risk. Permission to 00016 // use or copy this software for any purpose is hereby granted without 00017 // fee, provided the above notices are retained on all copies. 00018 // Permission to modify the code and to distribute modified code is 00019 // granted, provided the above notices are retained, and a notice that 00020 // the code was modified is included with the above copyright notice. 00021 // 00023 00058 /* 00059 * Copyright © 2002 Sofus Mortensen 00060 * 00061 * This material is provided "as is", with absolutely no warranty 00062 * expressed or implied. Any use is at your own risk. Permission to 00063 * use or copy this software for any purpose is hereby granted without 00064 * fee, provided the above notices are retained on all copies. 00065 * Permission to modify the code and to distribute modified code is 00066 * granted, provided the above notices are retained, and a notice that 00067 * the code was modified is included with the above copyright notice. 00068 * 00069 * This header is part of comet. 00070 * http://www.lambdasoft.dk/comet 00071 */ 00072 00073 #include <comet/config.h> 00074 #include <comet/assert.h> 00075 00076 #include <windows.h> 00077 00078 namespace comet { 00079 00080 #ifndef COMET_LW_LOCK_SPIN 00081 #define COMET_LW_LOCK_SPIN Sleep(0) 00082 #endif 00083 00086 00091 class lw_lock 00092 { 00093 // Interface 00094 00095 public: 00097 lw_lock() 00098 { 00099 reader_count_ = 0; 00100 writer_count_ = 0; 00101 } 00102 00104 ~lw_lock() 00105 { 00106 COMET_ASSERT( reader_count_ == 0 ); 00107 COMET_ASSERT( writer_count_ == 0 ); 00108 } 00109 00111 void enter_reader() const 00112 { 00113 while( 1 ) 00114 { 00115 // If there's a writer already, spin without unnecessarily 00116 // interlocking the CPUs 00117 00118 if( writer_count_ != 0 ) 00119 { 00120 COMET_LW_LOCK_SPIN; 00121 continue; 00122 } 00123 00124 // Add to the readers list 00125 00126 InterlockedIncrement((long *)&reader_count_ ); 00127 00128 // Check for writers again (we may have been pre-empted). If 00129 // there are no writers writing or waiting, then we're done. 00130 00131 if( writer_count_ == 0 ) 00132 break; 00133 00134 // Remove from the readers list, spin, try again 00135 00136 InterlockedDecrement((long *)&reader_count_ ); 00137 COMET_LW_LOCK_SPIN; 00138 } 00139 } 00140 00142 void leave_reader() const 00143 { 00144 InterlockedDecrement((long *)&reader_count_ ); 00145 } 00146 00148 void enter_writer() 00149 { 00150 // See if we can become the writer (expensive, because it inter- 00151 // locks the CPUs, so writing should be an infrequent process) 00152 00153 while( InterlockedExchange((long *)&writer_count_, 1 ) == 1 ) 00154 { 00155 COMET_LW_LOCK_SPIN; 00156 } 00157 00158 // Now we're the writer, but there may be outstanding readers. 00159 // Spin until there aren't any more; new readers will wait now 00160 // that we're the writer. 00161 00162 while( reader_count_ != 0 ) 00163 { 00164 COMET_LW_LOCK_SPIN; 00165 } 00166 } 00167 00169 void leave_writer() 00170 { 00171 writer_count_ = 0; 00172 } 00173 00174 // Implementation 00175 00176 private: 00177 mutable long volatile reader_count_; 00178 mutable long volatile writer_count_; 00179 00180 // Declare class non-copyable 00181 lw_lock(const lw_lock&); 00182 lw_lock& operator=(const lw_lock&); 00183 }; 00184 00189 class auto_reader_lock { 00190 public: 00191 explicit auto_reader_lock(const lw_lock& cs) : cs_(cs) { 00192 cs_.enter_reader(); 00193 } 00194 00195 ~auto_reader_lock() { 00196 cs_.leave_reader(); 00197 } 00198 00199 private: 00200 auto_reader_lock& operator=(const auto_reader_lock&); 00201 auto_reader_lock(const auto_reader_lock&); 00202 00203 const lw_lock& cs_; 00204 }; 00205 00210 class auto_writer_lock { 00211 public: 00212 explicit auto_writer_lock(lw_lock& cs) : cs_(cs) { 00213 cs_.enter_writer(); 00214 } 00215 00216 ~auto_writer_lock() { 00217 cs_.leave_writer(); 00218 } 00219 00220 private: 00221 auto_writer_lock& operator=(const auto_writer_lock&); 00222 auto_writer_lock(const auto_writer_lock&); 00223 00224 lw_lock& cs_; 00225 }; 00227 00228 }