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

Last change on this file since 1109 was 1109, checked in by sam, 11 years ago

build: for now, assume anything with <pthread.h> uses the pthread API.

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