00001 /* 00002 * threadsafe_multimap.h 00003 * 00004 * Copyright (C) 2010 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 multimap (wrapper around std::multimap) 00032 */ 00033 00034 #ifndef WAVEPACKET_THREADSAFE_MULTIMAP_H__ 00035 #define WAVEPACKET_THREADSAFE_MULTIMAP_H__ 00036 00037 // includes -------------------------------------------------------------------- 00038 #include "common/common.h" 00039 #include "smart_mutex.h" 00040 00041 00042 //////////////////////////////////////////////////////////////////////////////// 00043 /// 00044 /// \ingroup threadsafe 00045 /// 00046 /// A very simple map object that is safe for multiple threads to use at the 00047 /// same time. There is a single mutex protecting the entire map. 00048 /// 00049 /// You can iterate using getIterator()/getNextElement(). However, that is 00050 /// not guaranteed iteration. Your iterator will be invalidated (and 00051 /// getNextElement() will return false) if another thread has since updated 00052 /// the map. 00053 /// 00054 //////////////////////////////////////////////////////////////////////////////// 00055 template <class K, class T> 00056 class threadsafe_multimap : protected std::multimap<K,T> { 00057 private: 00058 // private typedefs ---------------------------------------------------- 00059 typedef std::multimap<K,T> base_map_t; 00060 typedef typename std::multimap<K,T>::iterator base_iterator_t; 00061 typedef typename std::pair<base_iterator_t, base_iterator_t> iter_pair_t; 00062 00063 public: 00064 // public typedefs ----------------------------------------------------- 00065 class iterator_t { 00066 public: 00067 friend class threadsafe_multimap<K, T>; 00068 private: 00069 base_iterator_t iter; // start at this element 00070 base_iterator_t end; // end before reaching here 00071 dword_t rvn; 00072 }; 00073 00074 // threadsafe_map class interface methods ------------------------------ 00075 00076 /// how many elements in the map 00077 int size(void) { 00078 // not a const operation because we touch the mutex 00079 mlock l(m_mutex); 00080 return base_map_t::size(); 00081 } 00082 00083 /// how many elements with the given key 00084 int count(IN const K& key) { 00085 mlock l(m_mutex); 00086 return base_map_t::count(key); 00087 } 00088 00089 /// insert the given object at the given key value 00090 void insert(IN const K& key, IN const T& t) { 00091 mlock l(m_mutex); 00092 ++m_rvn; 00093 base_map_t::insert(std::pair<K, T>(key, t)); 00094 } 00095 00096 /// remove (erase) all elements with this key 00097 void remove(IN const K& key) { 00098 mlock l(m_mutex); 00099 ++m_rvn; 00100 iter_pair_t pair = this->equal_range(key); 00101 base_map_t::erase(pair.first, pair.second); 00102 } 00103 00104 /// clear out (erase) the entire map 00105 void clear(void) { 00106 mlock l(m_mutex); 00107 ++m_rvn; 00108 base_map_t::clear(); 00109 } 00110 00111 /// get an iterator (points to the first element in the map) 00112 void getIterator(OUT iterator_t& i) { 00113 mlock l(m_mutex); 00114 i.rvn = m_rvn; 00115 i.iter = this->begin(); 00116 i.end = this->end(); 00117 } 00118 00119 /// get an iterator just for a particular key 00120 void getIterator(IN const K& key, OUT iterator_t& i) { 00121 mlock l(m_mutex); 00122 i.rvn = m_rvn; 00123 iter_pair_t pair = base_map_t::equal_range(key); 00124 i.iter = pair.first; 00125 i.end = pair.second; 00126 } 00127 00128 /// get next element in map and increment iterator 00129 bool getNextElement(IO iterator_t& i, OUT K& k, OUT T& t) { 00130 mlock l(m_mutex); 00131 T * pt = this->getNextElementInternal(i, k); 00132 if (!pt) 00133 return false; 00134 t = *pt; 00135 return true; 00136 } 00137 00138 /// get next element without getting a local copy. Caller had 00139 /// better be sure that the element won't be removed after 00140 /// this call! 00141 T * getNextElementUnsafe(IO iterator_t& i, OUT K& k) { 00142 mlock l(m_mutex); 00143 return this->getNextElementInternal(i, k); 00144 } 00145 00146 private: 00147 // private helper methods ---------------------------------------------- 00148 T * getNextElementInternal(IN iterator_t& i, OUT K& k) { 00149 // only used by other class methods! 00150 // caller should already have mutex 00151 if (i.rvn != this->m_rvn) 00152 return NULL; // iterator is now invalid! 00153 if (i.end == i.iter) 00154 return NULL; // end of iteration 00155 00156 // iterator is good! 00157 k = i.iter->first; 00158 T * t = &i.iter->second; 00159 ++i.iter; 00160 return t; 00161 } 00162 00163 // private member data ------------------------------------------------- 00164 smart_mutex m_mutex; 00165 dword_t m_rvn; 00166 }; 00167 00168 00169 #endif // WAVEPACKET_THREADSAFE_MULTIMAP_H__ 00170