1 // (C) Copyright 2013 Ruslan Baratov
2 // Copyright (C) 2014 Vicente J. Botet Escriba
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  See www.boost.org/libs/thread for documentation.
8 
9 #ifndef BOOST_THREAD_WITH_LOCK_GUARD_HPP
10 #define BOOST_THREAD_WITH_LOCK_GUARD_HPP
11 
12 #include <boost/thread/lock_guard.hpp>
13 #include <boost/utility/result_of.hpp>
14 //#include <boost/thread/detail/invoke.hpp>
15 
16 namespace boost {
17 
18 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
19     !defined(BOOST_NO_CXX11_DECLTYPE) && \
20     !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
21 
22 /**
23  * Utility to run functions in scope protected by mutex.
24  *
25  * Examples:
26  *
27  *     int func(int, int&);
28  *     boost::mutex m;
29  *     int a;
30  *     int result = boost::with_lock_guard(m, func, 1, boost::ref(a));
31  *
32  *     // using boost::bind
33  *     int result = boost::with_lock_guard(
34  *         m, boost::bind(func, 2, boost::ref(a))
35  *     );
36  *
37  *     // using lambda
38  *     int a;
39  *     int result = boost::with_lock_guard(
40  *         m,
41  *         [&a](int x) {
42  *           a = 3;
43  *           return x + 4;
44  *         },
45  *         5
46  *     );
47  */
48 template <class Lockable, class Function, class... Args>
with_lock_guard(Lockable & m,BOOST_FWD_REF (Function)func,BOOST_FWD_REF (Args)...args)49 typename boost::result_of<Function(Args...)>::type with_lock_guard(
50     Lockable& m,
51     BOOST_FWD_REF(Function) func,
52     BOOST_FWD_REF(Args)... args
53 ) //-> decltype(func(boost::forward<Args>(args)...))
54 {
55   boost::lock_guard<Lockable> lock(m);
56   return func(boost::forward<Args>(args)...);
57 }
58 
59 #else
60 
61 // Workaround versions for compilers without c++11 variadic templates support.
62 // (function arguments limit: 4)
63 // (for lambda support define BOOST_RESULT_OF_USE_DECLTYPE may be needed)
64 
65 template <class Lockable, class Func>
66 typename boost::result_of<Func()>::type with_lock_guard(
67     Lockable& m,
68     BOOST_FWD_REF(Func) func
69 ) {
70   boost::lock_guard<Lockable> lock(m);
71   return func();
72 }
73 
74 template <class Lockable, class Func, class Arg>
75 typename boost::result_of<Func(Arg)>::type with_lock_guard(
76     Lockable& m,
77     BOOST_FWD_REF(Func) func,
78     BOOST_FWD_REF(Arg) arg
79 ) {
80   boost::lock_guard<Lockable> lock(m);
81   return func(
82       boost::forward<Arg>(arg)
83   );
84 }
85 
86 template <class Lockable, class Func, class Arg1, class Arg2>
87 typename boost::result_of<Func(Arg1, Arg2)>::type with_lock_guard(
88     Lockable& m,
89     BOOST_FWD_REF(Func) func,
90     BOOST_FWD_REF(Arg1) arg1,
91     BOOST_FWD_REF(Arg2) arg2
92 ) {
93   boost::lock_guard<Lockable> lock(m);
94   return func(
95       boost::forward<Arg1>(arg1),
96       boost::forward<Arg2>(arg2)
97   );
98 }
99 
100 template <class Lockable, class Func, class Arg1, class Arg2, class Arg3>
101 typename boost::result_of<Func(Arg1, Arg2, Arg3)>::type with_lock_guard(
102     Lockable& m,
103     BOOST_FWD_REF(Func) func,
104     BOOST_FWD_REF(Arg1) arg1,
105     BOOST_FWD_REF(Arg2) arg2,
106     BOOST_FWD_REF(Arg3) arg3
107 ) {
108   boost::lock_guard<Lockable> lock(m);
109   return func(
110       boost::forward<Arg1>(arg1),
111       boost::forward<Arg2>(arg2),
112       boost::forward<Arg3>(arg3)
113   );
114 }
115 
116 template <
117     class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4
118 >
119 typename boost::result_of<Func(Arg1, Arg2, Arg3, Arg4)>::type with_lock_guard(
120     Lockable& m,
121     BOOST_FWD_REF(Func) func,
122     BOOST_FWD_REF(Arg1) arg1,
123     BOOST_FWD_REF(Arg2) arg2,
124     BOOST_FWD_REF(Arg3) arg3,
125     BOOST_FWD_REF(Arg4) arg4
126 ) {
127   boost::lock_guard<Lockable> lock(m);
128   return func(
129       boost::forward<Arg1>(arg1),
130       boost::forward<Arg2>(arg2),
131       boost::forward<Arg3>(arg3),
132       boost::forward<Arg4>(arg4)
133   );
134 }
135 
136 // overloads for function pointer
137 // (if argument is not function pointer, static assert will trigger)
138 template <class Lockable, class Func>
139 typename boost::result_of<
140     typename boost::add_pointer<Func>::type()
141 >::type with_lock_guard(
142     Lockable& m,
143     Func* func
144 ) {
145   BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
146 
147   boost::lock_guard<Lockable> lock(m);
148   return func();
149 }
150 
151 template <class Lockable, class Func, class Arg>
152 typename boost::result_of<
153     typename boost::add_pointer<Func>::type(Arg)
154 >::type with_lock_guard(
155     Lockable& m,
156     Func* func,
157     BOOST_FWD_REF(Arg) arg
158 ) {
159   BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
160 
161   boost::lock_guard<Lockable> lock(m);
162   return func(
163       boost::forward<Arg>(arg)
164   );
165 }
166 
167 template <class Lockable, class Func, class Arg1, class Arg2>
168 typename boost::result_of<
169     typename boost::add_pointer<Func>::type(Arg1, Arg2)
170 >::type with_lock_guard(
171     Lockable& m,
172     Func* func,
173     BOOST_FWD_REF(Arg1) arg1,
174     BOOST_FWD_REF(Arg2) arg2
175 ) {
176   BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
177 
178   boost::lock_guard<Lockable> lock(m);
179   return func(
180       boost::forward<Arg1>(arg1),
181       boost::forward<Arg2>(arg2)
182   );
183 }
184 
185 template <class Lockable, class Func, class Arg1, class Arg2, class Arg3>
186 typename boost::result_of<
187     typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3)
188 >::type with_lock_guard(
189     Lockable& m,
190     Func* func,
191     BOOST_FWD_REF(Arg1) arg1,
192     BOOST_FWD_REF(Arg2) arg2,
193     BOOST_FWD_REF(Arg3) arg3
194 ) {
195   BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
196 
197   boost::lock_guard<Lockable> lock(m);
198   return func(
199       boost::forward<Arg1>(arg1),
200       boost::forward<Arg2>(arg2),
201       boost::forward<Arg3>(arg3)
202   );
203 }
204 
205 template <
206     class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4
207 >
208 typename boost::result_of<
209     typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3, Arg4)
210 >::type with_lock_guard(
211     Lockable& m,
212     Func* func,
213     BOOST_FWD_REF(Arg1) arg1,
214     BOOST_FWD_REF(Arg2) arg2,
215     BOOST_FWD_REF(Arg3) arg3,
216     BOOST_FWD_REF(Arg4) arg4
217 ) {
218   BOOST_STATIC_ASSERT(boost::is_function<Func>::value);
219 
220   boost::lock_guard<Lockable> lock(m);
221   return func(
222       boost::forward<Arg1>(arg1),
223       boost::forward<Arg2>(arg2),
224       boost::forward<Arg3>(arg3),
225       boost::forward<Arg4>(arg4)
226   );
227 }
228 
229 #endif
230 
231 } // namespace boost
232 
233 #endif // BOOST_THREAD_WITH_LOCK_GUARD_HPP
234 
235