Ticket #2742: thread.hpp

File thread.hpp, 15.5 KB (added by anonymous, 13 years ago)
Line 
1#ifndef BOOST_THREAD_THREAD_COMMON_HPP
2#define BOOST_THREAD_THREAD_COMMON_HPP
3// Distributed under the Boost Software License, Version 1.0. (See
4// accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6// (C) Copyright 2007-8 Anthony Williams
7
8#include <boost/thread/exceptions.hpp>
9#include <ostream>
10#include <boost/thread/detail/move.hpp>
11#include <boost/thread/mutex.hpp>
12#include <boost/thread/xtime.hpp>
13#include <boost/thread/detail/thread_heap_alloc.hpp>
14#include <boost/utility.hpp>
15#include <boost/assert.hpp>
16#include <list>
17#include <algorithm>
18#include <boost/ref.hpp>
19#include <boost/cstdint.hpp>
20#include <boost/bind.hpp>
21#include <stdlib.h>
22#include <memory>
23#include <boost/utility/enable_if.hpp>
24#include <boost/type_traits/remove_reference.hpp>
25
26#include <boost/config/abi_prefix.hpp>
27
28#ifdef BOOST_MSVC
29#pragma warning(push)
30#pragma warning(disable:4251)
31#endif
32
33namespace boost
34{
35 namespace detail
36 {
37 template<typename F>
38 class thread_data:
39 public detail::thread_data_base
40 {
41 public:
42#ifdef BOOST_HAS_RVALUE_REFS
43 thread_data(F&& f_):
44 f(static_cast<F&&>(f_))
45 {}
46#else
47 thread_data(F f_):
48 f(f_)
49 {}
50 thread_data(detail::thread_move_t<F> f_):
51 f(f_)
52 {}
53#endif
54 void run()
55 {
56 f();
57 }
58 private:
59 F f;
60
61 void operator=(thread_data&);
62 thread_data(thread_data&);
63 };
64
65 template<typename F>
66 class thread_data<boost::reference_wrapper<F> >:
67 public detail::thread_data_base
68 {
69 private:
70 F& f;
71
72 void operator=(thread_data&);
73 thread_data(thread_data&);
74 public:
75 thread_data(boost::reference_wrapper<F> f_):
76 f(f_)
77 {}
78
79 void run()
80 {
81 f();
82 }
83 };
84
85 template<typename F>
86 class thread_data<const boost::reference_wrapper<F> >:
87 public detail::thread_data_base
88 {
89 private:
90 F& f;
91 void operator=(thread_data&);
92 thread_data(thread_data&);
93 public:
94 thread_data(const boost::reference_wrapper<F> f_):
95 f(f_)
96 {}
97
98 void run()
99 {
100 f();
101 }
102 };
103 }
104
105 class BOOST_THREAD_DECL thread
106 {
107 private:
108 thread(thread&);
109 thread& operator=(thread&);
110
111 void release_handle();
112
113 mutable boost::mutex thread_info_mutex;
114 detail::thread_data_ptr thread_info;
115
116 void start_thread();
117
118 explicit thread(detail::thread_data_ptr data);
119
120 detail::thread_data_ptr get_thread_info() const;
121
122#ifdef BOOST_HAS_RVALUE_REFS
123 template<typename F>
124 static inline detail::thread_data_ptr make_thread_info(F&& f)
125 {
126 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(static_cast<F&&>(f)));
127 }
128 static inline detail::thread_data_ptr make_thread_info(void (*f)())
129 {
130 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
131 }
132#else
133 template<typename F>
134 static inline detail::thread_data_ptr make_thread_info(F f)
135 {
136 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
137 }
138 template<typename F>
139 static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t<F> f)
140 {
141 return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
142 }
143
144 struct dummy;
145#endif
146 public:
147 thread();
148 ~thread();
149
150#ifdef BOOST_HAS_RVALUE_REFS
151 template <class F>
152 thread(F&& f):
153 thread_info(make_thread_info(static_cast<F&&>(f)))
154 {
155 start_thread();
156 }
157
158 thread(thread&& other)
159 {
160 thread_info.swap(other.thread_info);
161 }
162
163 thread& operator=(thread&& other)
164 {
165 thread_info=other.thread_info;
166 other.thread_info.reset();
167 return *this;
168 }
169
170 thread&& move()
171 {
172 return static_cast<thread&&>(*this);
173 }
174
175#else
176#ifdef BOOST_NO_SFINAE
177 template <class F>
178 explicit thread(F f):
179 thread_info(make_thread_info(f))
180 {
181 start_thread();
182 }
183#else
184 template <class F>
185 explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
186 thread_info(make_thread_info(f))
187 {
188 start_thread();
189 }
190#endif
191
192 template <class F>
193 explicit thread(detail::thread_move_t<F> f):
194 thread_info(make_thread_info(f))
195 {
196 start_thread();
197 }
198
199 thread(detail::thread_move_t<thread> x)
200 {
201 thread_info=x->thread_info;
202 x->thread_info.reset();
203 }
204
205 thread& operator=(detail::thread_move_t<thread> x)
206 {
207 thread new_thread(x);
208 swap(new_thread);
209 return *this;
210 }
211
212 operator detail::thread_move_t<thread>()
213 {
214 return move();
215 }
216
217 detail::thread_move_t<thread> move()
218 {
219 detail::thread_move_t<thread> x(*this);
220 return x;
221 }
222
223#endif
224
225 template <class F,class A1>
226 thread(F f,A1 a1):
227 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
228 {
229 start_thread();
230 }
231 template <class F,class A1,class A2>
232 thread(F f,A1 a1,A2 a2):
233 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
234 {
235 start_thread();
236 }
237
238 template <class F,class A1,class A2,class A3>
239 thread(F f,A1 a1,A2 a2,A3 a3):
240 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
241 {
242 start_thread();
243 }
244
245 template <class F,class A1,class A2,class A3,class A4>
246 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
247 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
248 {
249 start_thread();
250 }
251
252 template <class F,class A1,class A2,class A3,class A4,class A5>
253 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
254 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
255 {
256 start_thread();
257 }
258
259 template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
260 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
261 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
262 {
263 start_thread();
264 }
265
266 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
267 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
268 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
269 {
270 start_thread();
271 }
272
273 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
274 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
275 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
276 {
277 start_thread();
278 }
279
280 template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
281 thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
282 thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
283 {
284 start_thread();
285 }
286
287 void swap(thread& x)
288 {
289 thread_info.swap(x.thread_info);
290 }
291
292 class id;
293 id get_id() const;
294
295
296 bool joinable() const;
297 void join();
298 bool timed_join(const system_time& wait_until);
299
300 template<typename TimeDuration>
301 inline bool timed_join(TimeDuration const& rel_time)
302 {
303 return timed_join(get_system_time()+rel_time);
304 }
305 void detach();
306
307 static unsigned hardware_concurrency();
308
309 typedef detail::thread_data_base::native_handle_type native_handle_type;
310 native_handle_type native_handle();
311
312 // backwards compatibility
313 bool operator==(const thread& other) const;
314 bool operator!=(const thread& other) const;
315
316 static inline void yield()
317 {
318 this_thread::yield();
319 }
320
321 static inline void sleep(const system_time& xt)
322 {
323 this_thread::sleep(xt);
324 }
325
326 // extensions
327 void interrupt();
328 bool interruption_requested() const;
329 };
330
331 inline void swap(thread& lhs,thread& rhs)
332 {
333 return lhs.swap(rhs);
334 }
335
336#ifdef BOOST_HAS_RVALUE_REFS
337 inline thread&& move(thread&& t)
338 {
339 return t;
340 }
341#else
342 inline thread move(detail::thread_move_t<thread> t)
343 {
344 return thread(t);
345 }
346#endif
347
348 namespace this_thread
349 {
350 class BOOST_THREAD_DECL disable_interruption
351 {
352 disable_interruption(const disable_interruption&);
353 disable_interruption& operator=(const disable_interruption&);
354
355 bool interruption_was_enabled;
356 friend class restore_interruption;
357 public:
358 disable_interruption();
359 ~disable_interruption();
360 };
361
362 class BOOST_THREAD_DECL restore_interruption
363 {
364 restore_interruption(const restore_interruption&);
365 restore_interruption& operator=(const restore_interruption&);
366 public:
367 explicit restore_interruption(disable_interruption& d);
368 ~restore_interruption();
369 };
370
371 thread::id BOOST_THREAD_DECL get_id();
372
373 void BOOST_THREAD_DECL interruption_point();
374 bool BOOST_THREAD_DECL interruption_enabled();
375 bool BOOST_THREAD_DECL interruption_requested();
376
377 inline void sleep(xtime const& abs_time)
378 {
379 sleep(system_time(abs_time));
380 }
381 }
382
383 class thread::id
384 {
385 private:
386 detail::thread_data_ptr thread_data;
387
388 id(detail::thread_data_ptr thread_data_):
389 thread_data(thread_data_)
390 {}
391 friend class thread;
392 friend id this_thread::get_id();
393 public:
394 id():
395 thread_data()
396 {}
397
398 bool operator==(const id& y) const
399 {
400 return thread_data==y.thread_data;
401 }
402
403 bool operator!=(const id& y) const
404 {
405 return thread_data!=y.thread_data;
406 }
407
408 bool operator<(const id& y) const
409 {
410 return thread_data<y.thread_data;
411 }
412
413 bool operator>(const id& y) const
414 {
415 return y.thread_data<thread_data;
416 }
417
418 bool operator<=(const id& y) const
419 {
420 return !(y.thread_data<thread_data);
421 }
422
423 bool operator>=(const id& y) const
424 {
425 return !(thread_data<y.thread_data);
426 }
427
428 template<class charT, class traits>
429 friend std::basic_ostream<charT, traits>&
430 operator<<(std::basic_ostream<charT, traits>& os, const id& x)
431 {
432 if(x.thread_data)
433 {
434 return os<<x.thread_data;
435 }
436 else
437 {
438 return os<<"{Not-any-thread}";
439 }
440 }
441 };
442
443 inline bool thread::operator==(const thread& other) const
444 {
445 return get_id()==other.get_id();
446 }
447
448 inline bool thread::operator!=(const thread& other) const
449 {
450 return get_id()!=other.get_id();
451 }
452
453 namespace detail
454 {
455 struct thread_exit_function_base
456 {
457 virtual ~thread_exit_function_base()
458 {}
459 virtual void operator()() =0;
460 };
461
462 template<typename F>
463 struct thread_exit_function:
464 thread_exit_function_base
465 {
466 F f;
467
468 thread_exit_function(F f_):
469 f(f_)
470 {}
471
472 void operator()()
473 {
474 f();
475 }
476 };
477
478 void add_thread_exit_function(thread_exit_function_base*);
479 }
480
481 namespace this_thread
482 {
483 template<typename F>
484 void at_thread_exit(F f)
485 {
486 detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
487 detail::add_thread_exit_function(thread_exit_func);
488 }
489 }
490
491 class thread_group:
492 private noncopyable
493 {
494 public:
495 ~thread_group()
496 {
497 for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
498 it!=end;
499 ++it)
500 {
501 delete *it;
502 }
503 }
504
505 template<typename F>
506 thread* create_thread(F threadfunc)
507 {
508 boost::lock_guard<mutex> guard(m);
509 std::auto_ptr<thread> new_thread(new thread(threadfunc));
510 threads.push_back(new_thread.get());
511 return new_thread.release();
512 }
513
514 void add_thread(thread* thrd)
515 {
516 if(thrd)
517 {
518 boost::lock_guard<mutex> guard(m);
519 threads.push_back(thrd);
520 }
521 }
522
523 void remove_thread(thread* thrd)
524 {
525 boost::lock_guard<mutex> guard(m);
526 std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
527 if(it!=threads.end())
528 {
529 threads.erase(it);
530 }
531 }
532
533 void join_all()
534 {
535 boost::lock_guard<mutex> guard(m);
536
537 for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
538 it!=end;
539 ++it)
540 {
541 (*it)->join();
542 }
543 }
544
545 void interrupt_all()
546 {
547 boost::lock_guard<mutex> guard(m);
548
549 for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
550 it!=end;
551 ++it)
552 {
553 (*it)->interrupt();
554 }
555 }
556
557 size_t size() const
558 {
559 boost::lock_guard<mutex> guard(m);
560 return threads.size();
561 }
562
563 private:
564 std::list<thread*> threads;
565 mutable mutex m;
566 };
567}
568
569#ifdef BOOST_MSVC
570#pragma warning(pop)
571#endif
572
573#include <boost/config/abi_suffix.hpp>
574
575#endif