source: trunk/src/thread/threadbase.h @ 1101

Last change on this file since 1101 was 1101, checked in by gary, 9 years ago

core: implement Queue on Win32 and on the PS3.

  • Property svn:keywords set to Id
File size: 5.6 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11//
12// The ThreadBase class
13// --------------------
14//
15
16#if !defined __LOL_THREADBASE_H__
17#define __LOL_THREADBASE_H__
18
19#if defined __linux__ || defined __native_client__
20#   include <cstring>
21#   include <pthread.h>
22#elif defined _WIN32
23#   include <windows.h>
24#else
25#   error No threading support yet :(
26#endif
27
28namespace lol
29{
30
31class MutexBase
32{
33public:
34    MutexBase()
35    {
36#if defined __linux__ || defined __native_client__
37        pthread_mutex_init(&m_mutex, NULL);
38#elif defined _WIN32
39        InitializeCriticalSection(&m_mutex);
40#endif
41    }
42
43    ~MutexBase()
44    {
45#if defined __linux__ || defined __native_client__
46        pthread_mutex_destroy(&m_mutex);
47#elif defined _WIN32
48        DeleteCriticalSection(&m_mutex);
49#endif
50    }
51
52    void Lock()
53    {
54#if defined __linux__ || defined __native_client__
55        pthread_mutex_lock(&m_mutex);
56#elif defined _WIN32
57        EnterCriticalSection(&m_mutex);
58#endif
59    }
60
61    void Unlock()
62    {
63#if defined __linux__ || defined __native_client__
64        pthread_mutex_unlock(&m_mutex);
65#elif defined _WIN32
66        LeaveCriticalSection(&m_mutex);
67#endif
68    }
69
70private:
71#if defined __linux__ || defined __native_client__
72    pthread_mutex_t m_mutex;
73#elif defined _WIN32
74    CRITICAL_SECTION m_mutex;
75#endif
76};
77
78class QueueBase
79{
80public:
81    QueueBase()
82    {
83        m_start = m_count = 0;
84#if defined __linux__ || defined __native_client__
85        m_poppers = m_pushers = 0;
86        pthread_mutex_init(&m_mutex, NULL);
87        pthread_cond_init(&m_empty_cond, NULL);
88        pthread_cond_init(&m_full_cond, NULL);
89#elif defined _WIN32
90        m_empty_sem = CreateSemaphore(NULL, CAPACITY, CAPACITY, NULL);
91        m_full_sem = CreateSemaphore(NULL, 0, CAPACITY, NULL);
92        InitializeCriticalSection(&m_mutex);
93#endif
94    }
95
96    ~QueueBase()
97    {
98#if defined __linux__ || defined __native_client__
99        pthread_cond_destroy(&m_empty_cond);
100        pthread_cond_destroy(&m_full_cond);
101        pthread_mutex_destroy(&m_mutex);
102#elif defined _WIN32
103        CloseHandle(m_empty_sem);
104        CloseHandle(m_full_sem);
105        DeleteCriticalSection(&m_mutex);
106#endif
107    }
108
109    void Push(int value)
110    {
111#if defined __linux__ || defined __native_client__
112        pthread_mutex_lock(&m_mutex);
113        /* If queue is full, wait on the "full" cond var. */
114        m_pushers++;
115        while (m_count == CAPACITY)
116            pthread_cond_wait(&m_full_cond, &m_mutex);
117        m_pushers--;
118#elif defined _WIN32
119        WaitForSingleObject(m_empty_sem, INFINITE);
120        EnterCriticalSection(&m_mutex);
121#endif
122
123        /* Push value */
124        m_values[(m_start + m_count) % CAPACITY] = value;
125        m_count++;
126
127#if defined __linux__ || defined __native_client__
128        /* If there were poppers waiting, signal the "empty" cond var. */
129        if (m_poppers)
130            pthread_cond_signal(&m_empty_cond);
131        pthread_mutex_unlock(&m_mutex);
132#elif defined _WIN32
133        LeaveCriticalSection(&m_mutex);
134        ReleaseSemaphore(m_full_sem, 1, NULL);
135#endif
136    }
137
138    int Pop()
139    {
140#if defined __linux__ || defined __native_client__
141        pthread_mutex_lock(&m_mutex);
142        /* Wait until there is something in the queue. Be careful, we
143         * could get woken up but another thread may have eaten the
144         * message in the meantime. */
145        m_poppers++;
146        while (m_count == 0)
147            pthread_cond_wait(&m_empty_cond, &m_mutex);
148        m_poppers--;
149#elif defined _WIN32
150        WaitForSingleObject(m_full_sem, INFINITE);
151        EnterCriticalSection(&m_mutex);
152#endif
153
154        /* Pop value */
155        int ret = m_values[m_start];
156        m_start = (m_start + 1) % CAPACITY;
157        m_count--;
158
159#if defined __linux__ || defined __native_client__
160        /* If there were pushers waiting, signal the "full" cond var. */
161        if (m_pushers)
162            pthread_cond_signal(&m_full_cond);
163        pthread_mutex_unlock(&m_mutex);
164#else
165        LeaveCriticalSection(&m_mutex);
166        ReleaseSemaphore(m_empty_sem, 1, NULL);
167#endif
168
169        return ret;
170    }
171
172private:
173    static size_t const CAPACITY = 100;
174    int m_values[CAPACITY];
175    size_t m_start, m_count;
176#if defined __linux__ || defined __native_client__
177    size_t m_poppers, m_pushers;
178    pthread_mutex_t m_mutex;
179    pthread_cond_t m_empty_cond, m_full_cond;
180#elif defined _WIN32
181    HANDLE m_empty_sem, m_full_sem;
182    CRITICAL_SECTION m_mutex;
183#endif
184};
185
186class ThreadBase
187{
188public:
189    ThreadBase(void *(*fn)(void *), void *data)
190    {
191#if defined __linux__ || defined __native_client__
192        /* Set the joinable attribute for systems who don't play nice */
193        pthread_attr_t attr;
194        pthread_attr_init(&attr);
195        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
196        pthread_create(&m_thread, &attr, fn, data);
197#elif defined _WIN32
198        m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fn,
199                                data, 0, &m_tid);
200#endif
201    }
202
203    virtual ~ThreadBase()
204    {
205#if defined __linux__ || defined __native_client__
206        pthread_join(m_thread, NULL);
207#elif defined _WIN32
208        WaitForSingleObject(m_thread, INFINITE);
209#endif
210    }
211
212private:
213#if defined __linux__ || defined __native_client__
214    pthread_t m_thread;
215#elif defined _WIN32
216    HANDLE m_thread;
217    DWORD m_tid;
218#endif
219};
220
221} /* namespace lol */
222
223#endif // __LOL_THREADBASE_H__
224
Note: See TracBrowser for help on using the repository browser.