TFCweb  1.0.4 $Rev: 483 $
TFC Primavera 2012: Nucli d'un servidor web
CuaConcurrent.h
Veure la documentació d'aquest fitxer.
1 #if !defined(_CUA_CONCURRENT_H_)
2 #define _CUA_CONCURRENT_H_
3 
10 /*
11  * Copyright (c) 2012 Toni Corvera
12  *
13  * This file is part of TFCWeb.
14  *
15  * TFCWeb is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * TFCWeb is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with TFCWeb. If not, see <http://www.gnu.org/licenses/>.
27  */
28 
29 #include "portabilitat.h"
30 
31 #include <algorithm>
32 #include <deque>
33 #include <boost/thread.hpp>
34 
35 namespace tfc {
36 
37 // Nota: boost::unique_lock<boost::mutex> i boost::mutex::scoped_lock són equivalents
38 
39 // A diferència de la majoria del projecte es fan servir noms en anglès per
40 // apropar-se a la STL
41 // Altres fonts d'informació:
42 // - Implementació de cua concurrent sense locks: http://www.drdobbs.com/parallel/211601363
54 template<typename T, typename TContenidor = std::deque<T> >
56 private:
57  // Drecera
58  typedef boost::unique_lock<boost::mutex> scope_lock;
59 public:
60  // Tipus definits per els contenidors de la STL (només els que es fan servir)
61  typedef T value_type;
62  typedef T & reference;
63  typedef const T & const_reference;
64  typedef typename TContenidor::size_type size_type;
65 
66  typedef boost::posix_time::milliseconds milliseconds; // Drecera
67 
70  // buit
71  }
72 
75  {
76  //impl_.reserve(c.impl_.size());
77  scope_lock lock(c.mtx_);
78  // No cal blocar `this`
79  std::copy(c.impl_.begin(), c.impl_.end(), impl_.begin());
80  }
81 
82  virtual ~CuaConcurrent() {}
83 
95  bool pop(reference desti, const milliseconds & ms)
96  throw (boost::thread_exception, boost::thread_interrupted)
97  {
98  // Seria millor utilitzar scoped_timed_lock?
99  scope_lock lock(mtx_);
100  while (impl_.empty()) {
101  // Esperar notificació, desbloca mutex fins que retorni
102  const bool ok = cond_.timed_wait(lock, ms);
103  if (!ok) {
104  return false;
105  }
106  }
107  desti = impl_.front();
108  impl_.pop_front();
109  return true;
110  }
111 
120  void pop(reference desti)
121  throw (boost::thread_exception, boost::thread_interrupted)
122  {
123  scope_lock lock(mtx_);
124  while (impl_.empty()) {
125  cond_.wait(lock); // Esperar notificació, desbloca mutex fins que retorni
126  }
127  boost::posix_time::millisec(1);
128  desti = impl_.front();
129  impl_.pop_front();
130  }
131 
137  void push(const_reference element) {
138  scope_lock lock(mtx_);
139  const bool cal_notificar = impl_.empty();
140  impl_.push_back(element);
141  // alliberar assegura que el thread notificat pot accedir immediatament
142  lock.unlock();
143  if (cal_notificar) {
144  cond_.notify_one();
145  }
146  }
147 
155  bool try_pop(reference desti) {
156  boost::try_mutex::scoped_try_lock lock(mtx_);
157  if (!lock || impl_.empty()) {
158  return false;
159  }
160  desti = impl_.front();
161  impl_.pop_front();
162  return true;
163  }
164 
172  bool try_push(const_reference element) {
173  boost::try_mutex::scoped_try_lock lock(mtx_);
174  if (!lock) {
175  return false;
176  }
177  impl_.push_back(element);
178  return true;
179  }
180 
185  bool empty() const {
186  boost::mutex::scoped_lock lock(mtx_);
187  return impl_.empty();
188  }
189 
194  size_type size() const {
195  boost::mutex::scoped_lock lock(mtx_);
196  return impl_.size();
197  }
198 
199  // Degut a les "race conditions" no és recomanable utilitzar front() i back()
200 #if 0
201 
205  reference front() {
206  UNUSED boost::mutex::scoped_lock lock(mtx_);
207  return impl_.front();
208  }
209 
211  const_reference front() const {
212  // Cal blocar?
213  UNUSED boost::mutex::scoped_lock lock(mtx_);
214  return impl_.front();
215  }
216 
221  const_reference back() const {
222  UNUSED boost::mutex::scoped_lock lock(mtx_);
223  return impl_.back();
224  }
225 
227  reference back() {
228  UNUSED boost::mutex::scoped_lock lock(mtx_);
229  return impl_.back();
230  }
231 #endif
232 private:
233  TContenidor impl_;
234  boost::condition_variable cond_;
235  mutable boost::mutex mtx_;
236 };
237 
238 } // ns tfc
239 
240 #endif // _CUA_CONCURRENT_H_
241 
242 // vim:set ts=4 et ai: //