summaryrefslogtreecommitdiff
path: root/boost/thread/scoped_thread.hpp
blob: 6cda931a5f29dc3a0c8648ff4805bff85bca0d95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2009-2012 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba

// Based on the Anthony's idea of scoped_thread in CCiA

#ifndef BOOST_THREAD_SCOPED_THREAD_HPP
#define BOOST_THREAD_SCOPED_THREAD_HPP

#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/thread_functors.hpp>
#include <boost/thread/thread_only.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{

  /**
   * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
   *
   * CallableThread: A callable void(thread&) .
   * The default is a join_if_joinable.
   *
   * thread std/boost::thread destructor terminates the program if the thread is not joinable.
   * Having a wrapper that can join the thread before destroying it seems a natural need.
   *
   * Example:
   *
   *     boost::strict_scoped_thread<> t((boost::thread(F)));
   *
   */
  template <class CallableThread = join_if_joinable, class Thread=::boost::thread>
  class strict_scoped_thread
  {
    Thread t_;
    struct dummy;
  public:

    BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable

    /*
     *
     */
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
    template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type>
    explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
      t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
    template <class F>
    explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f,
        typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) :
      t_(boost::forward<F>(f)) {}
    template <class F, class A1>
    strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1)) {}
    template <class F, class A1, class A2>
    strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {}
    template <class F, class A1, class A2, class A3>
    strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {}
#endif

    /**
     * Constructor from the thread to own.
     *
     * @param t: the thread to own.
     *
     * Effects: move the thread to own @c t.
     */
    explicit strict_scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT :
    t_(boost::move(t))
    {
    }

    /**
     * Destructor
     * Effects: Call the CallableThread functor before destroying the owned thread.
     * Remark: The CallableThread should not throw when joining the thread as the scoped variable is on a scope outside the thread function.
     */
    ~strict_scoped_thread()
    {
      CallableThread on_destructor;

      on_destructor(t_);
    }

  };

  /**
   * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
   *
   * CallableThread: A callable void(thread&) .
   * The default is join_if_joinable.
   *
   * thread std::thread destructor terminates the program if the thread is not joinable.
   * Having a wrapper that can join the thread before destroying it seems a natural need.
   *
   * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type.
   * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the
   * same non-deprecated interface with the exception of the construction.
   *
   * Example:
   *
   *     boost::scoped_thread<> t((boost::thread(F)));
   *     t.interrupt();
   *
   */
  template <class CallableThread = join_if_joinable, class Thread=::boost::thread>
  class scoped_thread
  {
    Thread t_;
    struct dummy;
  public:

    typedef typename Thread::id id;
    typedef typename Thread::native_handle_type native_handle_type;

    BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only

    /**
     * Default Constructor.
     *
     * Effects: wraps a not-a-thread.
     */
    scoped_thread() BOOST_NOEXCEPT:
    t_()
    {
    }

    /**
     *
     */

#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
    template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type>
    explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
      t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
    template <class F>
    explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f,
        typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) :
      t_(boost::forward<F>(f)) {}
    template <class F, class A1>
    scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1)) {}
    template <class F, class A1, class A2>
    scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {}
    template <class F, class A1, class A2, class A3>
    scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) :
      t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {}

#endif
    /**
     * Constructor from the thread to own.
     *
     * @param t: the thread to own.
     *
     * Effects: move the thread to own @c t.
     */
    explicit scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT :
    t_(boost::move(t))
    {
    }

//    explicit operator Thread()
//    {
//      return boost::move(t_);
//    }

    /**
     * Move constructor.
     */
    scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT :
    t_(boost::move(BOOST_THREAD_RV(x).t_))
    {}

    /**
     * Destructor
     *
     * Effects: Call the CallableThread functor before destroying the owned thread.
     */
    ~scoped_thread()
    {
      CallableThread on_destructor;

      on_destructor(t_);
    }

    /**
     * Move assignment.
     */
    scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x)
    {
      CallableThread on_destructor;

      on_destructor(t_);
      t_ = boost::move(BOOST_THREAD_RV(x).t_);
      return *this;
    }

    /**
     *
     */
    void swap(scoped_thread& x) BOOST_NOEXCEPT
    {
      t_.swap(x.t_);
    }

    // forwarded thread functions
    inline id get_id() const BOOST_NOEXCEPT
    {
      return t_.get_id();
    }

    void detach()
    {
      t_.detach();
    }

    void join()
    {
      t_.join();
    }

#ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
    {
      return t_.try_join_for(rel_time);
    }

    template <class Clock, class Duration>
    bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time)
    {
      return t_.try_join_until(abs_time);
    }
#endif

    native_handle_type native_handle()BOOST_NOEXCEPT
    {
      return t_.native_handle();
    }

    bool joinable() const BOOST_NOEXCEPT
    {
      return t_.joinable();
    }

#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
    void interrupt()
    {
      t_.interrupt();
    }

    bool interruption_requested() const BOOST_NOEXCEPT
    {
      return t_.interruption_requested();
    }
#endif

    static unsigned hardware_concurrency() BOOST_NOEXCEPT
    {
      return Thread::hardware_concurrency();
    }

#ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY
    static unsigned physical_concurrency() BOOST_NOEXCEPT
    {
      return Thread::physical_concurrency();
    }
#endif
  };

  /**
   * Effects: swaps the contents of two scoped threads.
   */
  template <class Destroyer, class Thread >
  void swap(scoped_thread<Destroyer, Thread>& lhs, scoped_thread<Destroyer, Thread>& rhs)
BOOST_NOEXCEPT {
  return lhs.swap(rhs);
}

  typedef scoped_thread<> joining_thread;
}
#include <boost/config/abi_suffix.hpp>

#endif