5 // Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
16 // Test that header file is self-contained.
17 #include <boost/asio/strand.hpp>
20 #include <boost/asio/io_service.hpp>
21 #include <boost/asio/detail/thread.hpp>
22 #include "unit_test.hpp"
24 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
25 # include <boost/asio/deadline_timer.hpp>
26 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
27 # include <boost/asio/steady_timer.hpp>
28 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
30 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
31 # include <boost/bind.hpp>
32 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
33 # include <functional>
34 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
36 using namespace boost::asio;
37 typedef io_service::strand strand;
39 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
40 namespace bindns = boost;
41 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
42 namespace bindns = std;
45 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
46 typedef deadline_timer timer;
47 namespace chronons = boost::posix_time;
48 #elif defined(BOOST_ASIO_HAS_STD_CHRONO)
49 typedef steady_timer timer;
50 namespace chronons = std::chrono;
51 #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
52 typedef steady_timer timer;
53 namespace chronons = boost::chrono;
54 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
56 void increment(int* count)
61 void increment_without_lock(strand* s, int* count)
63 BOOST_ASIO_CHECK(!s->running_in_this_thread());
65 int original_count = *count;
67 s->dispatch(bindns::bind(increment, count));
69 // No other functions are currently executing through the locking dispatcher,
70 // so the previous call to dispatch should have successfully nested.
71 BOOST_ASIO_CHECK(*count == original_count + 1);
74 void increment_with_lock(strand* s, int* count)
76 BOOST_ASIO_CHECK(s->running_in_this_thread());
78 int original_count = *count;
80 s->dispatch(bindns::bind(increment, count));
82 // The current function already holds the strand's lock, so the
83 // previous call to dispatch should have successfully nested.
84 BOOST_ASIO_CHECK(*count == original_count + 1);
87 void sleep_increment(io_service* ios, int* count)
89 timer t(*ios, chronons::seconds(2));
95 void start_sleep_increments(io_service* ios, strand* s, int* count)
97 // Give all threads a chance to start.
98 timer t(*ios, chronons::seconds(2));
101 // Start three increments.
102 s->post(bindns::bind(sleep_increment, ios, count));
103 s->post(bindns::bind(sleep_increment, ios, count));
104 s->post(bindns::bind(sleep_increment, ios, count));
107 void throw_exception()
112 void io_service_run(io_service* ios)
123 ios.post(bindns::bind(increment_without_lock, &s, &count));
125 // No handlers can be called until run() is called.
126 BOOST_ASIO_CHECK(count == 0);
130 // The run() call will not return until all work has finished.
131 BOOST_ASIO_CHECK(count == 1);
135 s.post(bindns::bind(increment_with_lock, &s, &count));
137 // No handlers can be called until run() is called.
138 BOOST_ASIO_CHECK(count == 0);
142 // The run() call will not return until all work has finished.
143 BOOST_ASIO_CHECK(count == 1);
147 ios.post(bindns::bind(start_sleep_increments, &ios, &s, &count));
148 boost::asio::detail::thread thread1(bindns::bind(io_service_run, &ios));
149 boost::asio::detail::thread thread2(bindns::bind(io_service_run, &ios));
151 // Check all events run one after another even though there are two threads.
152 timer timer1(ios, chronons::seconds(3));
154 BOOST_ASIO_CHECK(count == 0);
155 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
157 BOOST_ASIO_CHECK(count == 1);
158 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
160 BOOST_ASIO_CHECK(count == 2);
165 // The run() calls will not return until all work has finished.
166 BOOST_ASIO_CHECK(count == 3);
169 int exception_count = 0;
171 s.post(throw_exception);
172 s.post(bindns::bind(increment, &count));
173 s.post(bindns::bind(increment, &count));
174 s.post(throw_exception);
175 s.post(bindns::bind(increment, &count));
177 // No handlers can be called until run() is called.
178 BOOST_ASIO_CHECK(count == 0);
179 BOOST_ASIO_CHECK(exception_count == 0);
194 // The run() calls will not return until all work has finished.
195 BOOST_ASIO_CHECK(count == 3);
196 BOOST_ASIO_CHECK(exception_count == 2);
201 // Check for clean shutdown when handlers posted through an orphaned strand
205 s2.post(bindns::bind(increment, &count));
206 s2.post(bindns::bind(increment, &count));
207 s2.post(bindns::bind(increment, &count));
210 // No handlers can be called until run() is called.
211 BOOST_ASIO_CHECK(count == 0);
214 BOOST_ASIO_TEST_SUITE
217 BOOST_ASIO_TEST_CASE(strand_test)