1 | // LAF Base Library |
2 | // Copyright (C) 2019-2021 Igara Studio S.A. |
3 | // Copyright (C) 2001-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifndef BASE_THREAD_H_INCLUDED |
9 | #define BASE_THREAD_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #if LAF_WINDOWS |
13 | #include "base/ints.h" |
14 | #endif |
15 | |
16 | namespace base { // Based on C++0x threads lib |
17 | |
18 | class thread { |
19 | public: |
20 | typedef void* native_handle_type; |
21 | #if LAF_WINDOWS |
22 | typedef uint32_t native_id_type; |
23 | #else |
24 | typedef void* native_id_type; |
25 | #endif |
26 | |
27 | // Create an instance to represent the current thread |
28 | thread(); |
29 | |
30 | // Create a new thread without arguments |
31 | template<class Callable> |
32 | thread(const Callable& f) { |
33 | launch_thread(new func_wrapper0<Callable>(f)); |
34 | } |
35 | |
36 | // Create a new thread with one argument |
37 | template<class Callable, class A> |
38 | thread(const Callable& f, A a) { |
39 | launch_thread(new func_wrapper1<Callable, A>(f, a)); |
40 | } |
41 | |
42 | // Create a new thread with two arguments |
43 | template<class Callable, class A, class B> |
44 | thread(const Callable& f, A a, B b) { |
45 | launch_thread(new func_wrapper2<Callable, A, B>(f, a, b)); |
46 | } |
47 | |
48 | ~thread(); |
49 | |
50 | bool joinable() const; |
51 | void join(); |
52 | void detach(); |
53 | |
54 | native_id_type native_id() const; |
55 | |
56 | class details { |
57 | public: |
58 | static void thread_proxy(void* data); |
59 | }; |
60 | |
61 | private: |
62 | native_handle_type m_native_handle; |
63 | #if LAF_WINDOWS |
64 | native_id_type m_native_id; |
65 | #endif |
66 | |
67 | class func_wrapper { |
68 | public: |
69 | virtual ~func_wrapper() { } |
70 | virtual void operator()() = 0; |
71 | }; |
72 | |
73 | void launch_thread(func_wrapper* f); |
74 | |
75 | template<class Callable> |
76 | class func_wrapper0 : public func_wrapper { |
77 | public: |
78 | Callable f; |
79 | func_wrapper0(const Callable& f) : f(f) { } |
80 | void operator()() { f(); } |
81 | }; |
82 | |
83 | template<class Callable, class A> |
84 | class func_wrapper1 : public func_wrapper { |
85 | public: |
86 | Callable f; |
87 | A a; |
88 | func_wrapper1(const Callable& f, A a) : f(f), a(a) { } |
89 | void operator()() { f(a); } |
90 | }; |
91 | |
92 | template<class Callable, class A, class B> |
93 | class func_wrapper2 : public func_wrapper { |
94 | public: |
95 | Callable f; |
96 | A a; |
97 | B b; |
98 | func_wrapper2(const Callable& f, A a, B b) : f(f), a(a), b(b) { } |
99 | void operator()() { f(a, b); } |
100 | }; |
101 | |
102 | }; |
103 | |
104 | namespace this_thread |
105 | { |
106 | void yield(); |
107 | void sleep_for(double seconds); |
108 | thread::native_id_type native_id(); |
109 | } |
110 | |
111 | // This class joins the thread in its destructor. |
112 | class thread_guard { |
113 | thread& m_thread; |
114 | public: |
115 | explicit thread_guard(thread& t) : m_thread(t) { } |
116 | ~thread_guard() |
117 | { |
118 | if (m_thread.joinable()) |
119 | m_thread.join(); |
120 | } |
121 | }; |
122 | |
123 | } |
124 | |
125 | #endif |
126 | |