Ticket #2742: thread.hpp

File thread.hpp, 15.5 KB (added by anonymous, 5 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