source: trunk/FACT++/src/queue.h@ 16936

Last change on this file since 16936 was 16562, checked in by tbretz, 11 years ago
Added a possibility to move an entry from another list into this list.
File size: 3.9 KB
Line 
1#ifndef FACT_Queue
2#define FACT_Queue
3
4#include <list>
5#include <thread>
6#include <condition_variable>
7
8template<class T>
9class Queue
10{
11 size_t fSize; // Only necessary for before C++11
12
13 std::list<T> fList;
14
15 std::mutex fMutex; // Mutex needed for the conditional
16 std::condition_variable fCond; // Conditional
17
18 enum state_t
19 {
20 kIdle,
21 kRun,
22 kStop,
23 kAbort,
24 };
25
26 state_t fState; // Stop signal for the thread
27
28 typedef std::function<void(const T &)> callback;
29 callback fCallback; // Callback function called by the thread
30
31 std::thread fThread; // Handle to the thread
32
33 void Thread()
34 {
35 std::unique_lock<std::mutex> lock(fMutex);
36
37 while (1)
38 {
39 while (fList.empty() && fState==kRun)
40 fCond.wait(lock);
41
42 if (fState==kAbort)
43 break;
44
45 if (fState==kStop && fList.empty())
46 break;
47
48 const T &val = fList.front();
49
50 // Theoretically, we can loose a signal here, but this is
51 // not a problem, because then we detect a non-empty queue
52 lock.unlock();
53
54 if (fCallback)
55 fCallback(val);
56
57 lock.lock();
58
59 fList.pop_front();
60 fSize--;
61 }
62
63 fList.clear();
64 fSize = 0;
65
66 fState = kIdle;
67 }
68
69public:
70 Queue(const callback &f) : fSize(0), fState(kIdle), fCallback(f)
71 {
72 start();
73 }
74 ~Queue()
75 {
76 wait(true);
77 }
78
79 bool start()
80 {
81 const std::lock_guard<std::mutex> lock(fMutex);
82 if (fState!=kIdle)
83 return false;
84
85 fState = kRun;
86 fThread = std::thread(std::bind(&Queue::Thread, this));
87 return true;
88 }
89
90 bool stop()
91 {
92 const std::lock_guard<std::mutex> lock(fMutex);
93 if (fState==kIdle)
94 return false;
95
96 fState = kStop;
97 fCond.notify_one();
98
99 return true;
100 }
101
102 bool abort()
103 {
104 const std::lock_guard<std::mutex> lock(fMutex);
105 if (fState==kIdle)
106 return false;
107
108 fState = kAbort;
109 fCond.notify_one();
110
111 return true;
112 }
113
114 bool wait(bool abrt=false)
115 {
116 {
117 const std::lock_guard<std::mutex> lock(fMutex);
118 if (fState==kIdle)
119 return false;
120
121 if (fState==kRun)
122 {
123 fState = abrt ? kAbort : kStop;
124 fCond.notify_one();
125 }
126 }
127
128 fThread.join();
129 return true;
130 }
131
132 bool post(const T &val)
133 {
134 const std::lock_guard<std::mutex> lock(fMutex);
135 if (fState==kIdle)
136 return false;
137
138 fList.push_back(val);
139 fSize++;
140
141 fCond.notify_one();
142
143 return true;
144 }
145
146#ifdef __GXX_EXPERIMENTAL_CXX0X__
147 template<typename... _Args>
148 bool emplace(_Args&&... __args)
149 {
150 const std::lock_guard<std::mutex> lock(fMutex);
151 if (fState==kIdle)
152 return false;
153
154 fList.emplace_back(__args...);
155 fSize++;
156
157 fCond.notify_one();
158
159 return true;
160 }
161
162 bool post(T &&val) { return emplace(std::move(val)); }
163#endif
164
165#ifdef __GXX_EXPERIMENTAL_CXX0X__
166 bool move(std::list<T>&& x, typename std::list<T>::iterator i)
167#else
168 bool move(std::list<T>& x, typename std::list<T>::iterator i)
169#endif
170 {
171 const std::lock_guard<std::mutex> lock(fMutex);
172 if (fState==kIdle)
173 return false;
174
175 fList.splice(fList.end(), x, i);
176 fSize++;
177
178 fCond.notify_one();
179
180 return true;
181 }
182
183#ifdef __GXX_EXPERIMENTAL_CXX0X__
184 bool move(std::list<T>& x, typename std::list<T>::iterator i) { return move(std::move(x), i); }
185#endif
186
187 size_t size() const
188 {
189 return fSize;
190 }
191
192 bool empty() const
193 {
194 return fSize==0;
195 }
196};
197
198#endif
Note: See TracBrowser for help on using the repository browser.