00001 /* 00002 * threadsafe_counter.h 00003 * 00004 * Copyright (C) 2008,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 * Implementation of a basic threadsafe counter, and a refcounter that uses it. 00032 */ 00033 00034 #ifndef WAVEPACKET_THREADSAFE_REFCOUNT_H__ 00035 #define WAVEPACKET_THREADSAFE_REFCOUNT_H__ 00036 00037 // includes -------------------------------------------------------------------- 00038 #include "common/common.h" 00039 #include "smart_mutex.h" 00040 00041 00042 /// \ingroup threadsafe 00043 /*@{*/ 00044 00045 /// Simple synchronized counter. Handy for any sort of counting that needs 00046 /// to be bumped up/down by different threads. 00047 class threadsafe_counter { 00048 public: 00049 threadsafe_counter(void) throw() : m_counter(0) { } 00050 00051 // public class methods ------------------------------------------------ 00052 00053 /// returns the authoritative count after the increment 00054 long increment(void) throw() { 00055 mlock l(m_mutex); 00056 ++m_counter; 00057 return m_counter; 00058 } 00059 00060 /// returns the authoritative count after the decrement 00061 long decrement(void) throw() { 00062 mlock l(m_mutex); 00063 --m_counter; 00064 return m_counter; 00065 } 00066 00067 /// currently non-authoritative! Not sure of a use case where that 00068 /// would help (other threads can change the count anyway) 00069 long getCount(void) const throw() { 00070 // any point in synchronizing here? Don't think so... 00071 return m_counter; 00072 } 00073 00074 private: 00075 // private member data ------------------------------------------------- 00076 smart_mutex m_mutex; 00077 long m_counter; 00078 }; 00079 00080 00081 00082 /// put one of these on the stack to automatically increment/decrement a counter 00083 class counter_ref { 00084 public: 00085 counter_ref(IN threadsafe_counter * ptc) throw() { 00086 ASSERT(ptc, "null"); 00087 m_ptc = ptc; 00088 m_ptc->increment(); 00089 } 00090 00091 ~counter_ref(void) throw() { 00092 ASSERT(m_ptc, "null"); 00093 m_ptc->decrement(); 00094 } 00095 00096 private: 00097 // private member data ------------------------------------------------- 00098 threadsafe_counter * m_ptc; 00099 }; 00100 00101 00102 00103 class threadsafe_refcount { 00104 public: 00105 // constructor, destructors -------------------------------------------- 00106 threadsafe_refcount(void) throw() : m_pcounter(NULL) { this->init(); } 00107 threadsafe_refcount(IN const threadsafe_refcount& trc) throw() : 00108 m_pcounter(NULL) { this->attach(trc); } 00109 ~threadsafe_refcount(void) throw() { this->release(); } 00110 00111 // public class methods ------------------------------------------------ 00112 long getRefCount(void) const throw() { 00113 if (!m_pcounter) { 00114 return 0; 00115 } 00116 return m_pcounter->getCount(); 00117 } 00118 00119 private: 00120 // private helper methods ---------------------------------------------- 00121 void release(void) throw() { 00122 if (m_pcounter) { 00123 long l = m_pcounter->decrement(); 00124 if (l < 1) { 00125 delete m_pcounter; 00126 } 00127 m_pcounter = 0; 00128 } 00129 } 00130 00131 void init(void) throw() { 00132 this->release(); 00133 m_pcounter = new threadsafe_counter; 00134 ASSERT(m_pcounter, "null"); 00135 m_pcounter->increment(); 00136 } 00137 00138 void attach(IN const threadsafe_refcount& trc) throw() { 00139 threadsafe_counter * ptc = trc.m_pcounter; 00140 ASSERT(ptc, "null"); 00141 m_pcounter = ptc; 00142 m_pcounter->increment(); 00143 } 00144 00145 // private member data ------------------------------------------------- 00146 threadsafe_counter * m_pcounter; 00147 }; 00148 00149 00150 #endif // WAVEPACKET_THREADSAFE_REFCOUNT_H__ 00151