root/lang/objective-cplusplus/i3/trunk/src/mil/include/mil/Thread.h @ 34853

Revision 34853, 5.6 kB (checked in by saturday06, 4 years ago)

pty

Line 
1#pragma once
2#include "Mil.h"
3#include "Serial.h"
4#include "Atomic.h"
5#include "FilterException.h"
6
7#ifndef MIL_MAX_THREADS
8#define MIL_MAX_THREADS 25
9#endif
10
11namespace mil {
12namespace thread {
13typedef intptr_t id_t;
14extern Serial id_serial;
15extern void* get(id_t thread_id);
16extern void set(id_t thread_id, void* object);
17extern bool is_valid_id(id_t thread_id);
18}
19}
20
21#if defined(MIL_OS_WINDOWS)
22#include "os-windows/Thread.h"
23#define MIL_DEFAULT_THREAD mil::thread::Windows
24//#elif defined(__CYGWIN__)
25//#include "os-windows/Thread.h"
26#elif defined(MIL_OS_UNIX)
27#include "os-unix/Thread.h"
28#define MIL_DEFAULT_THREAD mil::thread::Posix
29#else
30#error
31#endif
32
33#ifdef __OBJC__
34#include "gui-cocoa/CocoaThread.h"
35namespace mil {
36namespace thread {
37template <typename Child>
38class Cocoa : public boost::noncopyable {
39    MIL_CRTP_CLASS_MEMBERS;
40
41    WorkerThread* thread;
42
43public:
44    Cocoa() {
45        thread = [[WorkerThread alloc] init];
46    }
47
48    ~Cocoa() {
49        [thread release];
50    }
51
52    void start() {
53        struct foo {
54            static void* thread_routine(void* object) {
55                Child::thread_routine(object);
56                return NULL;
57            }
58        };
59
60        void* (*routine_)(void*) = foo::thread_routine;
61        void* arg_ = (void*)this;
62
63[thread setData:routine_ arg:arg_];
64[NSThread detachNewThreadSelector:@selector(start) toTarget:thread withObject:nil];
65    }
66
67    void join() {
68        for (int retry = 50; !getChild().is_exited.load(); retry--) {
69            if (retry == 0) {
70                halt << "thread can't exit";
71            }
72            sleep(1);
73        }
74    }
75};
76}
77}
78#endif
79
80#ifdef MIL_OS_UNIX
81
82namespace mil {
83namespace thread {
84
85typedef pid_t native_id_t;
86static inline native_id_t get_native_id() {
87    return gettid();
88}
89
90template <typename Child>
91class Posix : public boost::noncopyable {
92    pthread_t t;
93    pthread_attr_t a;
94
95    MIL_CRTP_CLASS_MEMBERS;
96
97public:
98    void start() {
99        struct foo {
100            static void* thread(void* object) {
101                Child::thread_routine(object);
102                return NULL;
103            }
104        };
105
106        pthread_attr_init(&a);
107        pthread_attr_setdetachstate(&a,PTHREAD_CREATE_DETACHED);
108        pthread_create(&t, &a, foo::thread,
109                       static_cast<void*>(this));
110    }
111
112    void join() {
113        for (int retry = 50; !getChild().is_exited.load(); retry--) {
114            if (retry == 0) {
115                halt << "thread can't exit";
116            }
117            sleep(1);
118        }
119    }
120};
121}
122}
123#endif
124
125#ifdef MIL_OS_WINDOWS
126namespace mil {
127namespace thread {
128
129typedef DWORD native_id_t;
130static inline native_id_t get_native_id() {
131    return GetCurrentThreadId();
132}
133
134template <typename Child>
135class Windows : public boost::noncopyable {
136public:
137    MIL_CRTP_CLASS_MEMBERS;
138
139protected:
140    atomic<HANDLE> hThread;
141
142public:
143    void start() {
144        struct foo {
145            static DWORD WINAPI thread(LPVOID object) {
146                Child::thread_routine(object);
147                return 0;
148            }
149        };
150
151        DWORD threadId;
152        LPVOID obj = reinterpret_cast<LPVOID>(this);
153        HANDLE t = CreateThread(NULL, 0, foo::thread, obj, 0, &threadId);
154        if (t == NULL) {
155            halt << "CreateThread(): failed";
156        }
157        hThread.store(t);
158    }
159
160    void join() {
161        HANDLE t = hThread.exchange(0);
162        if (!t) {
163            return;
164        }
165
166        for (int retry = 50; !getChild().is_exited.load(); retry--) {
167            if (retry == 0) {
168                MessageBox(NULL, _T("terminate thread"), _T(""), MB_OK);
169                //ExitProcess(1); // XXX
170                TerminateThread(t, 1);
171                break;
172            }
173            sleep(1);
174        }
175        CloseHandle(t);
176    }
177
178    Windows() : hThread(NULL) {
179    }
180};
181}
182}
183#endif
184
185namespace mil {
186template <class Child, template<class> class ThreadType = MIL_DEFAULT_THREAD>
187class Thread : public ThreadType<Thread<Child, ThreadType> > {
188public:
189    MIL_CRTP_CLASS_MEMBERS;
190
191    const thread::id_t thread_id;
192    atomic<bool> is_exited;
193
194    static int thread_routine_filtered(int, char** argv) {
195        Thread<Child, ThreadType>* obj = (Thread<Child, ThreadType>*)argv;
196        typedef Thread<Child, ThreadType> Type;
197
198        MIL_MODULE_SUPER_CHILD_TYPE(Type)& o =
199            MIL_MODULE_GET_SUPER_CHILD(*obj);
200
201        o.run();
202        o.is_exited.store(true);
203        //std::cout << "X" << std::flush;
204        return 0;
205    }
206
207    static void thread_routine(void* object) {
208        char** argv = reinterpret_cast<char**>(object);
209        filter_exception_and_start(0, argv, thread_routine_filtered);
210    }
211
212    void run() {
213    }
214
215    void start() {
216        if (!this->is_exited.load()) {
217            return;
218        }
219        this->is_exited.store(false);
220        //ThreadPlatform<Thread<Child> >::start();
221        ThreadType<Thread<Child, ThreadType> >::start();
222    }
223
224    Thread() : thread_id(thread::id_serial.retain()), is_exited(true) {
225        if (!thread::is_valid_id(thread_id)) {
226            halt << "can't retain thread id";
227            return;
228        }
229        //threads[thread_id].store(reinterpret_cast<void*>(this));
230        thread::set(thread_id, reinterpret_cast<void*>(this));
231    }
232
233    ~Thread() {
234        this->join();
235        thread::set(thread_id, NULL);
236        //threads[thread_id].store(NULL);
237        if (!thread::id_serial.release(thread_id)) {
238            halt << "can't release thread id";
239        }
240    }
241};
242}
243
Note: See TracBrowser for help on using the browser.