| 1 | // Copyright (C) 2001-2003 |
|---|
| 2 | // William E. Kempf |
|---|
| 3 | // |
|---|
| 4 | // Permission to use, copy, modify, distribute and sell this software |
|---|
| 5 | // and its documentation for any purpose is hereby granted without fee, |
|---|
| 6 | // provided that the above copyright notice appear in all copies and |
|---|
| 7 | // that both that copyright notice and this permission notice appear |
|---|
| 8 | // in supporting documentation. William E. Kempf makes no representations |
|---|
| 9 | // about the suitability of this software for any purpose. |
|---|
| 10 | // It is provided "as is" without express or implied warranty. |
|---|
| 11 | |
|---|
| 12 | #include <boost/thread/detail/config.hpp> |
|---|
| 13 | |
|---|
| 14 | #include <boost/thread/condition.hpp> |
|---|
| 15 | #include <boost/thread/thread.hpp> |
|---|
| 16 | #include <boost/thread/xtime.hpp> |
|---|
| 17 | |
|---|
| 18 | #include <boost/test/unit_test.hpp> |
|---|
| 19 | |
|---|
| 20 | #include <libs/thread/test/util.inl> |
|---|
| 21 | |
|---|
| 22 | struct condition_test_data |
|---|
| 23 | { |
|---|
| 24 | condition_test_data() : notified(0), awoken(0) { } |
|---|
| 25 | |
|---|
| 26 | boost::mutex mutex; |
|---|
| 27 | boost::condition condition; |
|---|
| 28 | int notified; |
|---|
| 29 | int awoken; |
|---|
| 30 | }; |
|---|
| 31 | |
|---|
| 32 | void condition_test_thread(condition_test_data* data) |
|---|
| 33 | { |
|---|
| 34 | boost::mutex::scoped_lock lock(data->mutex); |
|---|
| 35 | BOOST_CHECK(lock ? true : false); |
|---|
| 36 | while (!(data->notified > 0)) |
|---|
| 37 | data->condition.wait(lock); |
|---|
| 38 | BOOST_CHECK(lock ? true : false); |
|---|
| 39 | data->awoken++; |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | struct cond_predicate |
|---|
| 43 | { |
|---|
| 44 | cond_predicate(int& var, int val) : _var(var), _val(val) { } |
|---|
| 45 | |
|---|
| 46 | bool operator()() { return _var == _val; } |
|---|
| 47 | |
|---|
| 48 | int& _var; |
|---|
| 49 | int _val; |
|---|
| 50 | }; |
|---|
| 51 | |
|---|
| 52 | void condition_test_waits(condition_test_data* data) |
|---|
| 53 | { |
|---|
| 54 | boost::mutex::scoped_lock lock(data->mutex); |
|---|
| 55 | BOOST_CHECK(lock ? true : false); |
|---|
| 56 | |
|---|
| 57 | // Test wait. |
|---|
| 58 | while (data->notified != 1) |
|---|
| 59 | data->condition.wait(lock); |
|---|
| 60 | BOOST_CHECK(lock ? true : false); |
|---|
| 61 | BOOST_CHECK_EQUAL(data->notified, 1); |
|---|
| 62 | data->awoken++; |
|---|
| 63 | data->condition.notify_one(); |
|---|
| 64 | |
|---|
| 65 | // Test predicate wait. |
|---|
| 66 | data->condition.wait(lock, cond_predicate(data->notified, 2)); |
|---|
| 67 | BOOST_CHECK(lock ? true : false); |
|---|
| 68 | BOOST_CHECK_EQUAL(data->notified, 2); |
|---|
| 69 | data->awoken++; |
|---|
| 70 | data->condition.notify_one(); |
|---|
| 71 | |
|---|
| 72 | // Test timed_wait. |
|---|
| 73 | boost::xtime xt = delay(10); |
|---|
| 74 | while (data->notified != 3) |
|---|
| 75 | data->condition.timed_wait(lock, xt); |
|---|
| 76 | BOOST_CHECK(lock ? true : false); |
|---|
| 77 | BOOST_CHECK_EQUAL(data->notified, 3); |
|---|
| 78 | data->awoken++; |
|---|
| 79 | data->condition.notify_one(); |
|---|
| 80 | |
|---|
| 81 | // Test predicate timed_wait. |
|---|
| 82 | xt = delay(10); |
|---|
| 83 | cond_predicate pred(data->notified, 4); |
|---|
| 84 | BOOST_CHECK(data->condition.timed_wait(lock, xt, pred)); |
|---|
| 85 | BOOST_CHECK(lock ? true : false); |
|---|
| 86 | BOOST_CHECK(pred()); |
|---|
| 87 | BOOST_CHECK_EQUAL(data->notified, 4); |
|---|
| 88 | data->awoken++; |
|---|
| 89 | data->condition.notify_one(); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | void do_test_condition_notify_one() |
|---|
| 93 | { |
|---|
| 94 | condition_test_data data; |
|---|
| 95 | |
|---|
| 96 | boost::thread thread(bind(&condition_test_thread, &data)); |
|---|
| 97 | |
|---|
| 98 | { |
|---|
| 99 | boost::mutex::scoped_lock lock(data.mutex); |
|---|
| 100 | BOOST_CHECK(lock ? true : false); |
|---|
| 101 | data.notified++; |
|---|
| 102 | data.condition.notify_one(); |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | thread.join(); |
|---|
| 106 | BOOST_CHECK_EQUAL(data.awoken, 1); |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | void test_condition_notify_one() |
|---|
| 110 | { |
|---|
| 111 | timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex); |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | void do_test_condition_notify_all() |
|---|
| 115 | { |
|---|
| 116 | const int NUMTHREADS = 5; |
|---|
| 117 | boost::thread_group threads; |
|---|
| 118 | condition_test_data data; |
|---|
| 119 | |
|---|
| 120 | for (int i = 0; i < NUMTHREADS; ++i) |
|---|
| 121 | threads.create_thread(bind(&condition_test_thread, &data)); |
|---|
| 122 | |
|---|
| 123 | { |
|---|
| 124 | boost::mutex::scoped_lock lock(data.mutex); |
|---|
| 125 | BOOST_CHECK(lock ? true : false); |
|---|
| 126 | data.notified++; |
|---|
| 127 | data.condition.notify_all(); |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | threads.join_all(); |
|---|
| 131 | BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | void test_condition_notify_all() |
|---|
| 135 | { |
|---|
| 136 | // We should have already tested notify_one here, so |
|---|
| 137 | // a timed test with the default execution_monitor::use_condition |
|---|
| 138 | // should be OK, and gives the fastest performance |
|---|
| 139 | timed_test(&do_test_condition_notify_all, 3); |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | void do_test_condition_waits() |
|---|
| 143 | { |
|---|
| 144 | condition_test_data data; |
|---|
| 145 | |
|---|
| 146 | boost::thread thread(bind(&condition_test_waits, &data)); |
|---|
| 147 | |
|---|
| 148 | { |
|---|
| 149 | boost::mutex::scoped_lock lock(data.mutex); |
|---|
| 150 | BOOST_CHECK(lock ? true : false); |
|---|
| 151 | |
|---|
| 152 | boost::thread::sleep(delay(1)); |
|---|
| 153 | data.notified++; |
|---|
| 154 | data.condition.notify_one(); |
|---|
| 155 | while (data.awoken != 1) |
|---|
| 156 | data.condition.wait(lock); |
|---|
| 157 | BOOST_CHECK(lock ? true : false); |
|---|
| 158 | BOOST_CHECK_EQUAL(data.awoken, 1); |
|---|
| 159 | |
|---|
| 160 | boost::thread::sleep(delay(1)); |
|---|
| 161 | data.notified++; |
|---|
| 162 | data.condition.notify_one(); |
|---|
| 163 | while (data.awoken != 2) |
|---|
| 164 | data.condition.wait(lock); |
|---|
| 165 | BOOST_CHECK(lock ? true : false); |
|---|
| 166 | BOOST_CHECK_EQUAL(data.awoken, 2); |
|---|
| 167 | |
|---|
| 168 | boost::thread::sleep(delay(1)); |
|---|
| 169 | data.notified++; |
|---|
| 170 | data.condition.notify_one(); |
|---|
| 171 | while (data.awoken != 3) |
|---|
| 172 | data.condition.wait(lock); |
|---|
| 173 | BOOST_CHECK(lock ? true : false); |
|---|
| 174 | BOOST_CHECK_EQUAL(data.awoken, 3); |
|---|
| 175 | |
|---|
| 176 | boost::thread::sleep(delay(1)); |
|---|
| 177 | data.notified++; |
|---|
| 178 | data.condition.notify_one(); |
|---|
| 179 | while (data.awoken != 4) |
|---|
| 180 | data.condition.wait(lock); |
|---|
| 181 | BOOST_CHECK(lock ? true : false); |
|---|
| 182 | BOOST_CHECK_EQUAL(data.awoken, 4); |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | thread.join(); |
|---|
| 186 | BOOST_CHECK_EQUAL(data.awoken, 4); |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | void test_condition_waits() |
|---|
| 190 | { |
|---|
| 191 | // We should have already tested notify_one here, so |
|---|
| 192 | // a timed test with the default execution_monitor::use_condition |
|---|
| 193 | // should be OK, and gives the fastest performance |
|---|
| 194 | timed_test(&do_test_condition_waits, 12); |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) |
|---|
| 198 | { |
|---|
| 199 | boost::unit_test_framework::test_suite* test = |
|---|
| 200 | BOOST_TEST_SUITE("Boost.Threads: condition test suite"); |
|---|
| 201 | |
|---|
| 202 | test->add(BOOST_TEST_CASE(&test_condition_notify_one)); |
|---|
| 203 | test->add(BOOST_TEST_CASE(&test_condition_notify_all)); |
|---|
| 204 | test->add(BOOST_TEST_CASE(&test_condition_waits)); |
|---|
| 205 | |
|---|
| 206 | return test; |
|---|
| 207 | } |
|---|