00001
00002
00003
00004 #ifndef DMLITE_CPP_UTILS_POOLCONTAINER_H
00005 #define DMLITE_CPP_UTILS_POOLCONTAINER_H
00006
00007 #include <boost/thread/mutex.hpp>
00008 #include <boost/thread/condition.hpp>
00009 #include <map>
00010 #include <syslog.h>
00011 #include <queue>
00012 #include "../exceptions.h"
00013
00014 namespace dmlite {
00015
00016
00017
00018 template <class E>
00019 class PoolElementFactory {
00020 public:
00021
00022 virtual ~PoolElementFactory() {};
00023
00024
00025 virtual E create() = 0;
00026
00027
00028 virtual void destroy(E) = 0;
00029
00030
00031 virtual bool isValid(E) = 0;
00032 };
00033
00034
00035
00036 template <class E>
00037 class PoolContainer {
00038 public:
00039
00040
00041
00042 PoolContainer(PoolElementFactory<E>* factory, int n): max_(n), factory_(factory), freeSlots_(n)
00043 {
00044 }
00045
00046
00047 ~PoolContainer()
00048 {
00049
00050 while (free_.size() > 0) {
00051 E e = free_.front();
00052 free_.pop();
00053 factory_->destroy(e);
00054 }
00055
00056
00057 if (used_.size() > 0) {
00058 syslog(LOG_USER | LOG_WARNING, "%ld used elements from a pool not released on destruction!", (long)used_.size());
00059 }
00060 }
00061
00062
00063 E acquire(bool block = true)
00064 {
00065 E e;
00066
00067 if (!block && freeSlots_ == 0) {
00068 throw DmException(DMLITE_SYSERR(EBUSY),
00069 std::string("No resources available"));
00070 }
00071
00072 boost::mutex::scoped_lock lock(mutex_);
00073 while (freeSlots_ < 1)
00074 available_.wait(lock);
00075
00076
00077 if (free_.size() > 0) {
00078 e = free_.front();
00079 free_.pop();
00080
00081 if (!factory_->isValid(e)) {
00082 factory_->destroy(e);
00083 e = factory_->create();
00084 }
00085 }
00086 else {
00087
00088 e = factory_->create();
00089 }
00090
00091 used_.insert(std::pair<E, unsigned>(e, 1));
00092 --freeSlots_;
00093
00094 return e;
00095 }
00096
00097
00098 E acquire(E e)
00099 {
00100 boost::mutex::scoped_lock lock(mutex_);
00101
00102
00103 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00104 if (i == used_.end())
00105 throw DmException(DMLITE_SYSERR(EINVAL),
00106 std::string("The resource has not been locked previously!"));
00107
00108
00109 used_[e]++;
00110
00111
00112 return e;
00113 }
00114
00115
00116
00117
00118 unsigned release(E e)
00119 {
00120 boost::mutex::scoped_lock lock(mutex_);
00121
00122 unsigned remaining = --used_[e];
00123
00124 if (used_[e] == 0) {
00125
00126 used_.erase(e);
00127
00128 if ((long)free_.size() < max_) {
00129 free_.push(e);
00130 available_.notify_one();
00131 }
00132 else {
00133
00134 factory_->destroy(e);
00135 }
00136 }
00137 ++freeSlots_;
00138
00139 return remaining;
00140 }
00141
00142
00143 unsigned refCount(E e)
00144 {
00145 typename std::map<E, unsigned>::const_iterator i = used_.find(e);
00146 if (i == used_.end())
00147 return 0;
00148 return used_[e];
00149 }
00150
00151
00152
00153 void resize(int ns)
00154 {
00155
00156 boost::mutex::scoped_lock lock(mutex_);
00157 max_ = ns;
00158 freeSlots_ = max_ - used_.size();
00159
00160
00161 if (freeSlots_ > 0)
00162 available_.notify_all();
00163 }
00164
00165 private:
00166 int max_;
00167
00168 PoolElementFactory<E> *factory_;
00169
00170 std::queue<E> free_;
00171 std::map<E, unsigned> used_;
00172 unsigned freeSlots_;
00173
00174 boost::mutex mutex_;
00175 boost::condition_variable available_;
00176 };
00177
00178
00179 template <class E>
00180 class PoolGrabber {
00181 public:
00182 PoolGrabber(PoolContainer<E>& pool, bool block = true): pool_(pool)
00183 {
00184 element_ = pool_.acquire(block);
00185 }
00186
00187 ~PoolGrabber() {
00188 pool_.release(element_);
00189 }
00190
00191 operator E ()
00192 {
00193 return element_;
00194 }
00195
00196 private:
00197 PoolContainer<E>& pool_;
00198 E element_;
00199 };
00200 };
00201
00202 #endif // DMLITE_CPP_UTILS_POOLCONTAINER_H