libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
atomic_counter_parallel.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2011 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "core/thread_api_traits.hpp"
27 #include "core/thread_wrapper.hpp"
28 
29 using namespace libjmmcg;
30 using namespace ppd;
31 
32 typedef boost::mpl::list<
33  api_lock_traits<platform_api, heavyweight_threading>::atomic_counter_type<long>
34 > ctr_types;
35 
36 template<long exit_val, class Ctr>
37 struct inc_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
39 
40  Ctr &i;
41 
42  __stdcall inc_thread(Ctr &c) noexcept(true)
43  : base_t(), i(c) {
44  }
45  __stdcall ~inc_thread() noexcept(true) {
46  base_t::wait_thread_exit();
47  }
48 
49  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
50  for (unsigned long j=0; j<exit_val; ++j) {
51  ++i;
52  }
53  return true;
54  }
55 };
56 
57 template<long exit_val, long Inc, class Ctr>
58 struct inc_by_val_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
60 
61  Ctr &i;
62 
63  __stdcall inc_by_val_thread(Ctr &c) noexcept(true)
64  : base_t(), i(c) {
65  }
66  __stdcall ~inc_by_val_thread() noexcept(true) {
67  base_t::wait_thread_exit();
68  }
69 
70  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
71  for (unsigned long j=0; j<exit_val; ++j) {
72  i+=Inc;
73  }
74  return true;
75  }
76 };
77 
78 template<long exit_val, class Ctr>
79 struct dec_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
81 
82  Ctr &i;
83 
84  __stdcall dec_thread(Ctr &c) noexcept(true)
85  : base_t(), i(c) {
86  }
87  __stdcall ~dec_thread() noexcept(true) {
88  this->wait_thread_exit();
89  }
90 
91  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
92  for (unsigned long j=0; j<exit_val; ++j) {
93  --i;
94  }
95  return true;
96  }
97 };
98 
99 template<long exit_val, long Dec, class Ctr>
100 struct dec_by_val_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
102 
103  Ctr &i;
104 
105  __stdcall dec_by_val_thread(Ctr &c) noexcept(true)
106  : base_t(), i(c) {
107  }
108  __stdcall ~dec_by_val_thread() noexcept(true) {
109  this->wait_thread_exit();
110  }
111 
112  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
113  for (unsigned long j=0; j<exit_val; ++j) {
114  i-=Dec;
115  }
116  return true;
117  }
118 };
119 
120 BOOST_AUTO_TEST_SUITE(atomic_counter_parallel_tests)
121 
122 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_increments, ctr_t, ctr_types) {
123  const unsigned int check_value=100;
124  typedef inc_thread<check_value, ctr_t> inc_t;
125 
126  ctr_t c;
127  inc_t inc1(c);
128  inc_t inc2(c);
129  inc1.create_running();
130  inc2.create_running();
131  do {
132  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
133  } while (inc1.is_running() || inc2.is_running());
134  BOOST_CHECK_EQUAL(c.get(), 2*check_value);
135 }
136 
137 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_decrements, ctr_t, ctr_types) {
138  const unsigned long check_value=100;
139  typedef dec_thread<check_value, ctr_t> dec_t;
140 
141  ctr_t c(2*check_value);
142  dec_t dec1(c);
143  dec_t dec2(c);
144  dec1.create_running();
145  dec2.create_running();
146  do {
147  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
148  } while (dec1.is_running() || dec2.is_running());
149  BOOST_CHECK_EQUAL(c.get(), 0);
150 }
151 
152 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_inc_and_dec, ctr_t, ctr_types) {
153  const unsigned long check_value=100;
154  typedef inc_thread<check_value, ctr_t> inc_t;
155  typedef dec_thread<check_value, ctr_t> dec_t;
156 
157  ctr_t c(check_value);
158  inc_t inc(c);
159  dec_t dec(c);
160  inc.create_running();
161  dec.create_running();
162  do {
163  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
164  } while (inc.is_running() || dec.is_running());
165  BOOST_CHECK_EQUAL(c.get(), check_value);
166 }
167 
168 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_inc_and_dec_by_val, ctr_t, ctr_types) {
169  const unsigned long check_value=100;
170  const unsigned long delta=2;
171  typedef inc_by_val_thread<check_value, delta, ctr_t> inc_t;
172  typedef dec_by_val_thread<check_value, delta, ctr_t> dec_t;
173 
174  ctr_t c(delta*check_value);
175  inc_t inc(c);
176  dec_t dec(c);
177  inc.create_running();
178  dec.create_running();
179  do {
180  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
181  } while (inc.is_running() || dec.is_running());
182  BOOST_CHECK_EQUAL(c.get(), delta*check_value);
183 }
184 
185 BOOST_AUTO_TEST_SUITE_END()