1 // Comparison of bounded buffers based on different containers.
3 // Copyright (c) 2003-2008 Jan Gaspar
4 // Copyright 2013 Paul A. Bristow. Added some Quickbook snippet markers.
6 // Use, modification, and distribution is subject to the Boost Software
7 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
10 #include <boost/circular_buffer.hpp>
11 #include <boost/thread/mutex.hpp>
12 #include <boost/thread/condition.hpp>
13 #include <boost/thread/thread.hpp>
14 #include <boost/call_traits.hpp>
15 #include <boost/progress.hpp>
16 #include <boost/bind.hpp>
22 const unsigned long QUEUE_SIZE
= 1000L;
23 const unsigned long TOTAL_ELEMENTS
= QUEUE_SIZE
* 1000L;
26 class bounded_buffer
{
29 typedef boost::circular_buffer
<T
> container_type
;
30 typedef typename
container_type::size_type size_type
;
31 typedef typename
container_type::value_type value_type
;
32 typedef typename
boost::call_traits
<value_type
>::param_type param_type
;
34 explicit bounded_buffer(size_type capacity
) : m_unread(0), m_container(capacity
) {}
36 void push_front(param_type item
) {
37 boost::mutex::scoped_lock
lock(m_mutex
);
38 m_not_full
.wait(lock
, boost::bind(&bounded_buffer
<value_type
>::is_not_full
, this));
39 m_container
.push_front(item
);
42 m_not_empty
.notify_one();
45 void pop_back(value_type
* pItem
) {
46 boost::mutex::scoped_lock
lock(m_mutex
);
47 m_not_empty
.wait(lock
, boost::bind(&bounded_buffer
<value_type
>::is_not_empty
, this));
48 *pItem
= m_container
[--m_unread
];
50 m_not_full
.notify_one();
54 bounded_buffer(const bounded_buffer
&); // Disabled copy constructor
55 bounded_buffer
& operator = (const bounded_buffer
&); // Disabled assign operator
57 bool is_not_empty() const { return m_unread
> 0; }
58 bool is_not_full() const { return m_unread
< m_container
.capacity(); }
61 container_type m_container
;
63 boost::condition m_not_empty
;
64 boost::condition m_not_full
;
68 class bounded_buffer_space_optimized
{
71 typedef boost::circular_buffer_space_optimized
<T
> container_type
;
72 typedef typename
container_type::size_type size_type
;
73 typedef typename
container_type::value_type value_type
;
74 typedef typename
boost::call_traits
<value_type
>::param_type param_type
;
76 explicit bounded_buffer_space_optimized(size_type capacity
) : m_container(capacity
) {}
78 void push_front(param_type item
) {
79 boost::mutex::scoped_lock
lock(m_mutex
);
80 m_not_full
.wait(lock
, boost::bind(&bounded_buffer_space_optimized
<value_type
>::is_not_full
, this));
81 m_container
.push_front(item
);
83 m_not_empty
.notify_one();
86 void pop_back(value_type
* pItem
) {
87 boost::mutex::scoped_lock
lock(m_mutex
);
88 m_not_empty
.wait(lock
, boost::bind(&bounded_buffer_space_optimized
<value_type
>::is_not_empty
, this));
89 *pItem
= m_container
.back();
90 m_container
.pop_back();
92 m_not_full
.notify_one();
97 bounded_buffer_space_optimized(const bounded_buffer_space_optimized
&); // Disabled copy constructor
98 bounded_buffer_space_optimized
& operator = (const bounded_buffer_space_optimized
&); // Disabled assign operator
100 bool is_not_empty() const { return m_container
.size() > 0; }
101 bool is_not_full() const { return m_container
.size() < m_container
.capacity(); }
103 container_type m_container
;
104 boost::mutex m_mutex
;
105 boost::condition m_not_empty
;
106 boost::condition m_not_full
;
110 class bounded_buffer_deque_based
{
113 typedef std::deque
<T
> container_type
;
114 typedef typename
container_type::size_type size_type
;
115 typedef typename
container_type::value_type value_type
;
116 typedef typename
boost::call_traits
<value_type
>::param_type param_type
;
118 explicit bounded_buffer_deque_based(size_type capacity
) : m_capacity(capacity
) {}
120 void push_front(param_type item
) {
121 boost::mutex::scoped_lock
lock(m_mutex
);
122 m_not_full
.wait(lock
, boost::bind(&bounded_buffer_deque_based
<value_type
>::is_not_full
, this));
123 m_container
.push_front(item
);
125 m_not_empty
.notify_one();
128 void pop_back(value_type
* pItem
) {
129 boost::mutex::scoped_lock
lock(m_mutex
);
130 m_not_empty
.wait(lock
, boost::bind(&bounded_buffer_deque_based
<value_type
>::is_not_empty
, this));
131 *pItem
= m_container
.back();
132 m_container
.pop_back();
134 m_not_full
.notify_one();
139 bounded_buffer_deque_based(const bounded_buffer_deque_based
&); // Disabled copy constructor
140 bounded_buffer_deque_based
& operator = (const bounded_buffer_deque_based
&); // Disabled assign operator
142 bool is_not_empty() const { return m_container
.size() > 0; }
143 bool is_not_full() const { return m_container
.size() < m_capacity
; }
145 const size_type m_capacity
;
146 container_type m_container
;
147 boost::mutex m_mutex
;
148 boost::condition m_not_empty
;
149 boost::condition m_not_full
;
153 class bounded_buffer_list_based
{
156 typedef std::list
<T
> container_type
;
157 typedef typename
container_type::size_type size_type
;
158 typedef typename
container_type::value_type value_type
;
159 typedef typename
boost::call_traits
<value_type
>::param_type param_type
;
161 explicit bounded_buffer_list_based(size_type capacity
) : m_capacity(capacity
) {}
163 void push_front(param_type item
) {
164 boost::mutex::scoped_lock
lock(m_mutex
);
165 m_not_full
.wait(lock
, boost::bind(&bounded_buffer_list_based
<value_type
>::is_not_full
, this));
166 m_container
.push_front(item
);
168 m_not_empty
.notify_one();
171 void pop_back(value_type
* pItem
) {
172 boost::mutex::scoped_lock
lock(m_mutex
);
173 m_not_empty
.wait(lock
, boost::bind(&bounded_buffer_list_based
<value_type
>::is_not_empty
, this));
174 *pItem
= m_container
.back();
175 m_container
.pop_back();
177 m_not_full
.notify_one();
182 bounded_buffer_list_based(const bounded_buffer_list_based
&); // Disabled copy constructor
183 bounded_buffer_list_based
& operator = (const bounded_buffer_list_based
&); // Disabled assign operator
185 bool is_not_empty() const { return m_container
.size() > 0; }
186 bool is_not_full() const { return m_container
.size() < m_capacity
; }
188 const size_type m_capacity
;
189 container_type m_container
;
190 boost::mutex m_mutex
;
191 boost::condition m_not_empty
;
192 boost::condition m_not_full
;
195 template<class Buffer
>
198 typedef typename
Buffer::value_type value_type
;
203 Consumer(Buffer
* buffer
) : m_container(buffer
) {}
206 for (unsigned long i
= 0L; i
< TOTAL_ELEMENTS
; ++i
) {
207 m_container
->pop_back(&m_item
);
212 template<class Buffer
>
215 typedef typename
Buffer::value_type value_type
;
219 Producer(Buffer
* buffer
) : m_container(buffer
) {}
222 for (unsigned long i
= 0L; i
< TOTAL_ELEMENTS
; ++i
) {
223 m_container
->push_front(value_type());
228 template<class Buffer
>
229 void fifo_test(Buffer
* buffer
) {
231 // Start of measurement
232 boost::progress_timer progress
;
234 // Initialize the buffer with some values before launching producer and consumer threads.
235 for (unsigned long i
= QUEUE_SIZE
/ 2L; i
> 0; --i
) {
236 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581))
237 buffer
->push_front(Buffer::value_type());
239 buffer
->push_front(BOOST_DEDUCED_TYPENAME
Buffer::value_type());
243 Consumer
<Buffer
> consumer(buffer
);
244 Producer
<Buffer
> producer(buffer
);
246 // Start the threads.
247 boost::thread
consume(consumer
);
248 boost::thread
produce(producer
);
250 // Wait for completion.
254 // End of measurement
257 int main(int /*argc*/, char* /*argv*/[]) {
259 bounded_buffer
<int> bb_int(QUEUE_SIZE
);
260 std::cout
<< "bounded_buffer<int> ";
263 bounded_buffer_space_optimized
<int> bb_space_optimized_int(QUEUE_SIZE
);
264 std::cout
<< "bounded_buffer_space_optimized<int> ";
265 fifo_test(&bb_space_optimized_int
);
267 bounded_buffer_deque_based
<int> bb_deque_based_int(QUEUE_SIZE
);
268 std::cout
<< "bounded_buffer_deque_based<int> ";
269 fifo_test(&bb_deque_based_int
);
271 bounded_buffer_list_based
<int> bb_list_based_int(QUEUE_SIZE
);
272 std::cout
<< "bounded_buffer_list_based<int> ";
273 fifo_test(&bb_list_based_int
);
275 bounded_buffer
<std::string
> bb_string(QUEUE_SIZE
);
276 std::cout
<< "bounded_buffer<std::string> ";
277 fifo_test(&bb_string
);
279 bounded_buffer_space_optimized
<std::string
> bb_space_optimized_string(QUEUE_SIZE
);
280 std::cout
<< "bounded_buffer_space_optimized<std::string> ";
281 fifo_test(&bb_space_optimized_string
);
283 bounded_buffer_deque_based
<std::string
> bb_deque_based_string(QUEUE_SIZE
);
284 std::cout
<< "bounded_buffer_deque_based<std::string> ";
285 fifo_test(&bb_deque_based_string
);
287 bounded_buffer_list_based
<std::string
> bb_list_based_string(QUEUE_SIZE
);
288 std::cout
<< "bounded_buffer_list_based<std::string> ";
289 fifo_test(&bb_list_based_string
);
295 //[bounded_buffer_comparison_output
297 Description: Autorun "J:\Cpp\Misc\Debug\bounded_buffer_comparison.exe"
298 bounded_buffer<int> 5.15 s
300 bounded_buffer_space_optimized<int> 5.71 s
302 bounded_buffer_deque_based<int> 15.57 s
304 bounded_buffer_list_based<int> 17.33 s
306 bounded_buffer<std::string> 24.49 s
308 bounded_buffer_space_optimized<std::string> 28.33 s
310 bounded_buffer_deque_based<std::string> 29.45 s
312 bounded_buffer_list_based<std::string> 31.29 s
314 //] //[bounded_buffer_comparison_output]