Code::Blocks  SVN r11506
backgroundthread.h
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  */
5 
6 #ifndef BACKGROUNDTHREAD_H
7 #define BACKGROUNDTHREAD_H
8 
9 #include "safedelete.h"
10 
11 #undef new
12 #include <deque>
13 #include <list>
14 #include <algorithm>
15 
16 #include <wx/timer.h> // wxMilliSleep
17 #include "wx/thread.h"
18 #include "manager.h"
19 #include "blockallocated.h"
20 
21 /*
22 * BackgroundThread is a lightweight single background worker thread implementation for situations in which
23 * you simply want to do one or several things in another thread, and using a thread pool is overkill.
24 * Also, several BackgroundThreads can be used in situations where a thread pool is unsuitable by design. For example,
25 * you can use two BackgroundThreads to asynchronously read a list of files from disk one at at time and download another list
26 * of files from the internet without hogging either the hard disk or the network layer with more than one concurrent access.
27 *
28 * BackgroundThread can be configured to own the job objects (will delete them after running) or not. It can also own
29 * the semaphore and queue, or use a shared context.
30 *
31 * BackgroundThreadPool is a low overhead thread pool implementation around BackgroundThread.
32 */
33 
34 
36 {
37 public:
39  virtual ~AbstractJob(){};
40  virtual void operator()() = 0;
41 };
42 
43 
44 
45 class JobQueue : public std::deque<AbstractJob*>
46 {
48 
49 public:
50  void Push(AbstractJob *j)
51  {
53  push_back(j);
54  };
56  {
58  AbstractJob* j = front();
59  pop_front();
60  return j;
61  };
62 };
63 
64 
65 
66 class BackgroundThread : public wxThread
67 {
70  bool die;
71  const bool ownsQueue;
72  const bool ownsSemaphore;
73  const bool ownsJobs;
74 
75 public:
76  BackgroundThread(JobQueue *q, wxSemaphore *s, const bool owns_jobs = true)
77  : queue(q), semaphore(s), die(false), ownsQueue(false), ownsSemaphore(false), ownsJobs(owns_jobs)
78  {
79  Create();
80  Run();
81  };
82 
83  BackgroundThread(wxSemaphore *s, const bool owns_jobs = true)
84  : queue(new JobQueue), semaphore(s), die(false), ownsQueue(true), ownsSemaphore(false), ownsJobs(owns_jobs)
85  {
86  Create();
87  Run();
88  };
89 
90  BackgroundThread(JobQueue *q, const bool owns_jobs = true)
91  : queue(q), semaphore(new wxSemaphore), die(false), ownsQueue(false), ownsSemaphore(true), ownsJobs(owns_jobs)
92  {
93  Create();
94  Run();
95  };
96 
97  BackgroundThread(const bool owns_jobs = true)
98  : queue(new JobQueue), semaphore(new wxSemaphore), die(false), ownsQueue(true), ownsSemaphore(true), ownsJobs(owns_jobs)
99  {
100  Create();
101  Run();
102  };
103 
104  ~BackgroundThread() override
105  {
106  if (ownsSemaphore)
107  ::Delete(semaphore);
108  if (ownsQueue)
109  ::Delete(queue);
110  };
111 
112 
114  {
115  queue->Push(j);
116  semaphore->Post();
117  };
118 
119  void Die()
120  {
121  die = true;
122  semaphore->Post();
123  wxMilliSleep(0);
124  };
125 
126 
127  void MarkDying() // Need this for threadpool. Die() alone does not work in shared context (for obvious reason).
128  {
129  die = true;
130  };
131 
132 
133  ExitCode Entry() override
134  {
135  AbstractJob* job;
136  for (;;)
137  {
138  semaphore->Wait();
139  if (die)
140  break;
141 
142  job = queue->Pop();
143  if ( job )
144  (*job)();
145 
146  if (ownsJobs)
147  delete job;
148  }
149  return nullptr;
150  };
151 };
152 
153 
154 
155 
156 
157 struct Agony { inline void operator()(BackgroundThread* t){t->MarkDying();}; };
158 struct Death { inline void operator()(BackgroundThread* t){t->Die();}; };
159 
161 {
162  typedef std::list<BackgroundThread*> ThreadList;
163 
166  ThreadList threadList;
167 
168 public:
169  BackgroundThreadPool(size_t num_threads = 4)
170  {
171  for (unsigned int i = 0; i < num_threads; ++i)
172  AddThread(new BackgroundThread(&queue, &semaphore));
173  };
174 
176  {
177  for_each(threadList.begin(), threadList.end(), Agony());
178  for_each(threadList.begin(), threadList.end(), Death());
179  Delete(queue);
180  wxMilliSleep(0);
181  };
182 
184  {
185  threadList.push_back(t);
186  };
187 
189  {
190  queue.Push(j);
191  semaphore.Post();
192  };
193 };
194 
195 
196 
197 #endif
198 
void Queue(AbstractJob *j)
const bool ownsQueue
BackgroundThread(JobQueue *q, const bool owns_jobs=true)
void Delete(std::vector< T > &s)
Definition: safedelete.h:20
BackgroundThreadPool(size_t num_threads=4)
std::list< BackgroundThread * > ThreadList
BackgroundThread(const bool owns_jobs=true)
void operator()(BackgroundThread *t)
wxSemaphore * semaphore
wxSemaError Post()
const bool ownsSemaphore
void Push(AbstractJob *j)
virtual ~AbstractJob()
ExitCode Entry() override
void Queue(AbstractJob *j)
void AddThread(BackgroundThread *t)
void operator()(BackgroundThread *t)
AbstractJob * Pop()
~BackgroundThread() override
BackgroundThread(JobQueue *q, wxSemaphore *s, const bool owns_jobs=true)
BackgroundThread(wxSemaphore *s, const bool owns_jobs=true)
void wxMilliSleep(unsigned long milliseconds)
wxSemaError Wait()
virtual void operator()()=0
wxCriticalSection c
void * ExitCode