• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 boost::once_flag flag=BOOST_ONCE_INIT;
19 int var_to_init=0;
20 boost::mutex m;
21 
initialize_variable()22 void 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 
call_once_thread()30 void 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, &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 
BOOST_AUTO_TEST_CASE(test_call_once)47 BOOST_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(&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 
72 int var_to_init_with_functor=0;
73 
74 struct increment_value
75 {
76     int* value;
increment_valueincrement_value77     explicit increment_value(int* value_):
78         value(value_)
79     {}
80 
operator ()increment_value81     void operator()() const
82     {
83         boost::unique_lock<boost::mutex> lock(m);
84         ++(*value);
85     }
86 };
87 
call_once_with_functor()88 void 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(functor_flag, 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 
BOOST_AUTO_TEST_CASE(test_call_once_arbitrary_functor)106 BOOST_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(&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 
132 struct throw_before_third_pass
133 {
134     struct my_exception
135     {};
136 
137     static unsigned pass_counter;
138 
operator ()throw_before_third_pass139     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 
150 unsigned throw_before_third_pass::pass_counter=0;
151 unsigned exception_counter=0;
152 
call_once_with_exception()153 void call_once_with_exception()
154 {
155     static boost::once_flag functor_flag=BOOST_ONCE_INIT;
156     try
157     {
158         boost::call_once(functor_flag, 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 
BOOST_AUTO_TEST_CASE(test_call_once_retried_on_exception)167 BOOST_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(&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