MPD  0.20.18
WorkQueue.hxx
Go to the documentation of this file.
1 /*
2  * Copyright 2003-2017 The Music Player Daemon Project
3  * http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef _WORKQUEUE_H_INCLUDED_
21 #define _WORKQUEUE_H_INCLUDED_
22 
23 #include "thread/Mutex.hxx"
24 #include "thread/Cond.hxx"
25 
26 #include <assert.h>
27 #include <pthread.h>
28 
29 #include <string>
30 #include <queue>
31 
32 #define LOGINFO(X)
33 #define LOGERR(X)
34 
48 template <class T>
49 class WorkQueue {
50  // Configuration
51  const std::string name;
52 
53  // Status
54  // Worker threads having called exit
55  unsigned n_workers_exited = 0;
56  bool ok = false;
57 
58  unsigned n_threads = 0;
59  pthread_t *threads = nullptr;
60 
61  // Synchronization
62  std::queue<T> queue;
63  Cond client_cond;
64  Cond worker_cond;
65  Mutex mutex;
66 
67 public:
71  explicit WorkQueue(const char *_name)
72  :name(_name)
73  {
74  }
75 
78  }
79 
80  WorkQueue(const WorkQueue &) = delete;
81  WorkQueue &operator=(const WorkQueue &) = delete;
82 
91  bool start(unsigned nworkers, void *(*workproc)(void *), void *arg)
92  {
93  const std::lock_guard<Mutex> protect(mutex);
94 
95  assert(nworkers > 0);
96  assert(!ok);
97  assert(n_threads == 0);
98  assert(threads == nullptr);
99 
100  ok = true;
101  n_threads = nworkers;
102  threads = new pthread_t[n_threads];
103 
104  for (unsigned i = 0; i < nworkers; i++) {
105  int err;
106  if ((err = pthread_create(&threads[i], 0, workproc, arg))) {
107  LOGERR(("WorkQueue:%s: pthread_create failed, err %d\n",
108  name.c_str(), err));
109  return false;
110  }
111  }
112 
113  return true;
114  }
115 
120  template<typename U>
121  bool put(U &&u)
122  {
123  const std::lock_guard<Mutex> protect(mutex);
124 
125  queue.emplace(std::forward<U>(u));
126 
127  // Just wake one worker, there is only one new task.
128  worker_cond.signal();
129 
130  return true;
131  }
132 
133 
137  {
138  const std::lock_guard<Mutex> protect(mutex);
139 
140  // Wait for all worker threads to have called workerExit()
141  ok = false;
142  while (n_workers_exited < n_threads) {
143  worker_cond.broadcast();
144  client_cond.wait(mutex);
145  }
146 
147  // Perform the thread joins and compute overall status
148  // Workers return (void*)1 if ok
149  for (unsigned i = 0; i < n_threads; ++i) {
150  void *status;
151  pthread_join(threads[i], &status);
152  }
153 
154  delete[] threads;
155  threads = nullptr;
156  n_threads = 0;
157 
158  // Reset to start state.
159  n_workers_exited = 0;
160  }
161 
167  bool take(T &tp)
168  {
169  const std::lock_guard<Mutex> protect(mutex);
170 
171  if (!ok)
172  return false;
173 
174  while (queue.empty()) {
175  worker_cond.wait(mutex);
176  if (!ok)
177  return false;
178  }
179 
180  tp = std::move(queue.front());
181  queue.pop();
182  return true;
183  }
184 
193  void workerExit()
194  {
195  const std::lock_guard<Mutex> protect(mutex);
196 
197  n_workers_exited++;
198  ok = false;
199  client_cond.broadcast();
200  }
201 };
202 
203 #endif /* _WORKQUEUE_H_INCLUDED_ */
void workerExit()
Advertise exit and abort queue.
Definition: WorkQueue.hxx:193
#define LOGERR(X)
Definition: WorkQueue.hxx:33
bool put(U &&u)
Add item to work queue, called from client.
Definition: WorkQueue.hxx:121
A WorkQueue manages the synchronisation around a queue of work items, where a number of client thread...
Definition: WorkQueue.hxx:49
void wait(PosixMutex &mutex)
Definition: PosixCond.hxx:73
Definition: Cond.hxx:41
Definition: Mutex.hxx:43
void setTerminateAndWait()
Tell the workers to exit, and wait for them.
Definition: WorkQueue.hxx:136
bool take(T &tp)
Take task from queue.
Definition: WorkQueue.hxx:167
bool start(unsigned nworkers, void *(*workproc)(void *), void *arg)
Start the worker threads.
Definition: WorkQueue.hxx:91
void signal()
Definition: PosixCond.hxx:65
WorkQueue(const char *_name)
Create a WorkQueue.
Definition: WorkQueue.hxx:71
void broadcast()
Definition: PosixCond.hxx:69
WorkQueue & operator=(const WorkQueue &)=delete
const Partition const char * name
Definition: Count.hxx:34