00001 /* 00002 * threadsafe_map.h 00003 * 00004 * Copyright (C) 2007,2009 Thomas A. Vaughan 00005 * All rights reserved. 00006 * 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * * Neither the name of the <organization> nor the 00016 * names of its contributors may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY 00020 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY 00023 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00026 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * 00031 * Basic threadsafe map (wrapper around std::map) 00032 */ 00033 00034 #ifndef WAVEPACKET_THREADSAFE_MAP_H__ 00035 #define WAVEPACKET_THREADSAFE_MAP_H__ 00036 00037 // includes -------------------------------------------------------------------- 00038 #include "common/common.h" 00039 #include "smart_mutex.h" 00040 00041 #include <pthread.h> 00042 00043 //////////////////////////////////////////////////////////////////////////////// 00044 /// 00045 /// threadsafe map object 00046 /// 00047 /// \ingroup threadsafe 00048 /// 00049 /// A very simple map object that is safe for multiple threads to use at the 00050 /// same time. There is a single mutex protecting the entire map. 00051 /// 00052 /// You can iterate using getIterator()/getNextElement(). However, that is 00053 /// not guaranteed iteration. Your iterator will be invalidated (and 00054 /// getNextElement() will return false) if another thread has since updated 00055 /// the map. 00056 /// 00057 //////////////////////////////////////////////////////////////////////////////// 00058 template <class K, class T> 00059 class threadsafe_map : protected std::map<K,T> { 00060 private: 00061 // private typedefs ---------------------------------------------------- 00062 typedef std::map<K,T> base_map_t; 00063 typedef typename std::map<K,T>::iterator base_iterator_t; 00064 typedef threadsafe_map<K, T> map_t; 00065 00066 struct real_iter_t { 00067 base_iterator_t iter; 00068 dword_t rvn; 00069 }; 00070 00071 public: 00072 // public typedefs ----------------------------------------------------- 00073 struct iterator_t { 00074 protected: 00075 byte_t opaque[sizeof(real_iter_t)]; 00076 }; 00077 00078 // threadsafe_map class interface methods ------------------------------ 00079 00080 /// how many elements in the map 00081 int size(void) const throw() { 00082 map_t * pThis = this->getNonConst(); 00083 mlock l(pThis->m_mutex); 00084 return base_map_t::size(); 00085 } 00086 00087 /// insert the given object at the given key value (map, not multimap!) 00088 void insert(IN const K& key, IN const T& t) { 00089 mlock l(m_mutex); 00090 ++m_rvn; 00091 this->operator[](key) = t; 00092 } 00093 00094 /// retrieve value at key--true if there is a value there 00095 bool lookup(IN const K& key, OUT T& t) const throw() { 00096 map_t * pThis = this->getNonConst(); 00097 mlock l(pThis->m_mutex); 00098 base_iterator_t i = pThis->find(key); 00099 if (pThis->end() != i) { 00100 t = i->second; // note: caller gets a copy! 00101 return true; 00102 } 00103 return false; // not found! 00104 } 00105 00106 /// remove (erase) the element at key, if there is one 00107 bool remove(IN const K& key) { 00108 mlock l(m_mutex); 00109 base_iterator_t i = this->find(key); 00110 if (this->end() != i) { 00111 ++m_rvn; 00112 this->erase(i); 00113 return true; 00114 } 00115 return false; 00116 } 00117 00118 /// clear out (erase) the entire map 00119 void clear(void) { 00120 mlock l(m_mutex); 00121 ++m_rvn; 00122 base_map_t::clear(); 00123 } 00124 00125 /// get an iterator (points to the first element in the map) 00126 void getIterator(OUT iterator_t& i) const throw() { 00127 map_t * pThis = this->getNonConst(); 00128 real_iter_t * ri = getRealIterator(i); 00129 mlock l(pThis->m_mutex); 00130 ri->rvn = m_rvn; 00131 ri->iter = pThis->begin(); 00132 } 00133 00134 /// get next element in map and increment iterator 00135 bool getNextElement(IO iterator_t& i, OUT K& k, OUT T& t) const { 00136 map_t * pThis = this->getNonConst(); 00137 real_iter_t * ri = getRealIterator(i); 00138 mlock l(pThis->m_mutex); 00139 if (ri->rvn != this->m_rvn) 00140 return false; // iterator is now invalid! 00141 if (pThis->end() == ri->iter) 00142 return false; // end of iteration 00143 00144 // iterator is good! 00145 k = ri->iter->first; 00146 t = ri->iter->second; 00147 ++ri->iter; 00148 return true; 00149 } 00150 00151 /// for debugging/validation only 00152 static int getRealIteratorSize(void) throw() { 00153 return sizeof(real_iter_t); 00154 } 00155 00156 private: 00157 // private helper methods ---------------------------------------------- 00158 static real_iter_t * getRealIterator(IN iterator_t& i) throw() { 00159 return (real_iter_t *) &i; 00160 } 00161 00162 // cast to avoid const-ness. This is because read-only operations need 00163 // to hold the mutex 00164 map_t * getNonConst(void) const throw() { 00165 return (map_t *) this; 00166 } 00167 00168 // private member data ------------------------------------------------- 00169 smart_mutex m_mutex; 00170 dword_t m_rvn; 00171 }; 00172 00173 00174 #endif // WAVEPACKET_THREADSAFE_MAP_H__ 00175