1// (C) Copyright 2006-7 Anthony Williams
2// Distributed under the Boost Software License, Version 1.0. (See
3// accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6#define BOOST_THREAD_VERSION 2
7#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
8#define BOOST_TEST_MODULE Boost.Threads: once test suite
9
10#include <boost/test/unit_test.hpp>
11#include <boost/thread/thread.hpp>
12#include <boost/thread/mutex.hpp>
13#include <boost/thread/once.hpp>
14#include <iostream>
15
16#include <boost/thread/detail/log.hpp>
17
18boost::once_flag flag=BOOST_ONCE_INIT;
19int var_to_init=0;
20boost::mutex m;
21
22void initialize_variable()
23{
24 // ensure that if multiple threads get in here, they are serialized, so we can see the effect
25 boost::unique_lock<boost::mutex> lock(m);
26 ++var_to_init;
27}
28
29
30void call_once_thread()
31{
32 unsigned const loop_count=100;
33 int my_once_value=0;
34 for(unsigned i=0;i<loop_count;++i)
35 {
36 boost::call_once(flag, f: &initialize_variable);
37 my_once_value=var_to_init;
38 if(my_once_value!=1)
39 {
40 break;
41 }
42 }
43 boost::unique_lock<boost::mutex> lock(m);
44 BOOST_CHECK_EQUAL(my_once_value, 1);
45}
46
47BOOST_AUTO_TEST_CASE(test_call_once)
48{
49 BOOST_DETAIL_THREAD_LOG;
50
51 unsigned const num_threads=20;
52 boost::thread_group group;
53
54 try
55 {
56 for(unsigned i=0;i<num_threads;++i)
57 {
58 group.create_thread(threadfunc: &call_once_thread);
59 }
60 group.join_all();
61 }
62 catch(...)
63 {
64 group.interrupt_all();
65 group.join_all();
66 throw;
67 }
68
69 BOOST_CHECK_EQUAL(var_to_init,1);
70}
71
72int var_to_init_with_functor=0;
73
74struct increment_value
75{
76 int* value;
77 explicit increment_value(int* value_):
78 value(value_)
79 {}
80
81 void operator()() const
82 {
83 boost::unique_lock<boost::mutex> lock(m);
84 ++(*value);
85 }
86};
87
88void call_once_with_functor()
89{
90 unsigned const loop_count=100;
91 int my_once_value=0;
92 static boost::once_flag functor_flag=BOOST_ONCE_INIT;
93 for(unsigned i=0;i<loop_count;++i)
94 {
95 boost::call_once(flag&: functor_flag, f: increment_value(&var_to_init_with_functor));
96 my_once_value=var_to_init_with_functor;
97 if(my_once_value!=1)
98 {
99 break;
100 }
101 }
102 boost::unique_lock<boost::mutex> lock(m);
103 BOOST_CHECK_EQUAL(my_once_value, 1);
104}
105
106BOOST_AUTO_TEST_CASE(test_call_once_arbitrary_functor)
107{
108 BOOST_DETAIL_THREAD_LOG;
109
110 unsigned const num_threads=20;
111 boost::thread_group group;
112
113 try
114 {
115 for(unsigned i=0;i<num_threads;++i)
116 {
117 group.create_thread(threadfunc: &call_once_with_functor);
118 }
119 group.join_all();
120 }
121 catch(...)
122 {
123 group.interrupt_all();
124 group.join_all();
125 throw;
126 }
127
128 BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
129}
130
131
132struct throw_before_third_pass
133{
134 struct my_exception
135 {};
136
137 static unsigned pass_counter;
138
139 void operator()() const
140 {
141 boost::unique_lock<boost::mutex> lock(m);
142 ++pass_counter;
143 if(pass_counter<3)
144 {
145 throw my_exception();
146 }
147 }
148};
149
150unsigned throw_before_third_pass::pass_counter=0;
151unsigned exception_counter=0;
152
153void call_once_with_exception()
154{
155 static boost::once_flag functor_flag=BOOST_ONCE_INIT;
156 try
157 {
158 boost::call_once(flag&: functor_flag, f: throw_before_third_pass());
159 }
160 catch(throw_before_third_pass::my_exception)
161 {
162 boost::unique_lock<boost::mutex> lock(m);
163 ++exception_counter;
164 }
165}
166
167BOOST_AUTO_TEST_CASE(test_call_once_retried_on_exception)
168{
169 BOOST_DETAIL_THREAD_LOG;
170 unsigned const num_threads=20;
171 boost::thread_group group;
172
173 try
174 {
175 for(unsigned i=0;i<num_threads;++i)
176 {
177 group.create_thread(threadfunc: &call_once_with_exception);
178 }
179 group.join_all();
180 }
181 catch(...)
182 {
183 group.interrupt_all();
184 group.join_all();
185 throw;
186 }
187
188 BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
189 BOOST_CHECK_EQUAL(exception_counter,2u);
190}
191
192
193

source code of boost/libs/thread/test/test_once.cpp