TFCweb  1.0.4 $Rev: 483 $
TFC Primavera 2012: Nucli d'un servidor web
ThreadPool.cc
Veure la documentació d'aquest fitxer.
1 
8 /*
9  * Copyright (c) 2012 Toni Corvera
10  *
11  * This file is part of TFCWeb.
12  *
13  * TFCWeb is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * TFCWeb is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with TFCWeb. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "Log.h"
28 #include "ThreadPool.h"
29 
30 #include <iostream>
31 #include <boost/lexical_cast.hpp>
32 
33 using namespace std;
34 using boost::lexical_cast;
35 
36 namespace {
37 
38 using namespace tfc;
39 
40 enum {
43 };
44 
45 class WorkerThread {
46 public:
47  // Nota: En la construcció encara estem en el thread principal!
49  volatile bool * marca_de_final)
50  : tasques(q), terminat_(marca_de_final)
51  {
52  assert( 0 != terminat_ );
53  }
54 
56  : tasques(wt.tasques), terminat_(wt.terminat_)
57  {
58  assert( 0 != terminat_ );
59  }
60 
61  void operator()() {
62  using boost::posix_time::milliseconds;
63  //cerr << "Executant thread " << boost::this_thread::get_id() << endl;
64  assert( 0 != terminat_ );
65  while (! *terminat_) {
67  // INVARIANT:
69  const bool ok = tasques.pop(tasca, milliseconds(INTERVAL_TIMEOUT));
70  if (ok) {
71  tasca();
72  }
73  }
74  }
75 
76 private:
78  volatile bool * terminat_;
79 };
80 
81 } // ns anònim
82 
83 namespace tfc {
84 
85 ThreadPool::ThreadPool(const size_t num_threads)
86  : n_threads_(num_threads), tancada_(false), marca_terminacio_(false)
87 {
88  inicia();
89 }
90 
92  termina();
93  join(); // Cal esperar que finalitzin per no tenir efectes extranys
94  for (size_t i=0; i<n_threads_; ++i) {
95  delete threads_[i];
96  }
97 }
98 
100  // INVARIANT:
102  if (tancada_) {
103  throw ErrorThreadPoolTancada();
104  }
105  tasques_.push(tasca);
106 }
107 
109  threads_.reserve(n_threads_);
110  for (size_t i=0; i<n_threads_; ++i) {
111  threads_.push_back( new boost::thread(WorkerThread(tasques_, &marca_terminacio_)) );
112  }
113 }
114 
116  tancada_ = true;
117 }
118 
120  tanca(); // No més tasques
121  // TODO: Millor mètode?
122  // Esperem que es finalitzin les tasques (o que s'indiqui finalització immediata)...
123  while (!tasques_.empty() && !marca_terminacio_) {
124  boost::this_thread::sleep(boost::posix_time::milliseconds(INTERVAL_POLLING));
125  }
126  // ... i terminem els workers
127  termina();
128  // join sobre cada thread
129  for_each(threads_.begin(), threads_.end(), std::mem_fun<void>(&boost::thread::join));
130 }
131 
133  tanca(); // No més tasques
134  marca_terminacio_ = true;
135 }
136 
137 } // ns tfc
138 
139 // vim:set ts=4 et ai: //