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

Last change on this file since 1099 was 1099, checked in by sam, 9 years ago

core: make the Queue object work with several producers, and get rid of
the idiotic memmove() we were using.

  • Property svn:keywords set to Id
File size: 4.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#if defined __linux__ || defined __native_client__
84        memset(m_values, 0, sizeof(m_values));
85        m_start = m_count = 0;
86        m_poppers = m_pushers = 0;
87        pthread_mutex_init(&m_mutex, NULL);
88        pthread_cond_init(&m_empty_cond, NULL);
89        pthread_cond_init(&m_full_cond, NULL);
90#endif
91    }
92
93    ~QueueBase()
94    {
95#if defined __linux__ || defined __native_client__
96        pthread_cond_destroy(&m_empty_cond);
97        pthread_cond_destroy(&m_full_cond);
98        pthread_mutex_destroy(&m_mutex);
99#endif
100    }
101
102    void Push(int value)
103    {
104#if defined __linux__ || defined __native_client__
105        pthread_mutex_lock(&m_mutex);
106        /* If queue is full, wait on the "full" cond var. */
107        m_pushers++;
108        while (m_count == 100)
109            pthread_cond_wait(&m_full_cond, &m_mutex);
110        m_pushers--;
111        /* Push value */
112        m_values[(m_start + m_count) % 100] = value;
113        m_count++;
114        /* If there were poppers waiting, signal the "empty" cond var. */
115        if (m_poppers)
116            pthread_cond_signal(&m_empty_cond);
117        pthread_mutex_unlock(&m_mutex);
118#endif
119    }
120
121    int Pop()
122    {
123#if defined __linux__ || defined __native_client__
124        pthread_mutex_lock(&m_mutex);
125        /* Wait until there is something in the queue. Be careful, we
126         * could get woken up but another thread may have eaten the
127         * message in the meantime. */
128        m_poppers++;
129        while (m_count == 0)
130            pthread_cond_wait(&m_empty_cond, &m_mutex);
131        m_poppers--;
132        /* Pop value */
133        int ret = m_values[m_start];
134        m_start = (m_start + 1) % 100;
135        m_count--;
136        /* If there were pushers waiting, signal the "full" cond var. */
137        if (m_pushers)
138            pthread_cond_signal(&m_full_cond);
139        pthread_mutex_unlock(&m_mutex);
140        return ret;
141#endif
142    }
143
144private:
145#if defined __linux__ || defined __native_client__
146    int m_values[100];
147    size_t m_poppers, m_pushers, m_start, m_count;
148    pthread_mutex_t m_mutex;
149    pthread_cond_t m_empty_cond, m_full_cond;
150#endif
151};
152
153class ThreadBase
154{
155public:
156    ThreadBase(void *(*fn)(void *), void *data)
157    {
158#if defined __linux__ || defined __native_client__
159        /* Set the joinable attribute for systems who don't play nice */
160        pthread_attr_t attr;
161        pthread_attr_init(&attr);
162        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
163        pthread_create(&m_thread, &attr, fn, data);
164#elif defined _WIN32
165        m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fn,
166                                data, 0, &m_tid);
167#endif
168    }
169
170    virtual ~ThreadBase()
171    {
172#if defined __linux__ || defined __native_client__
173        pthread_join(m_thread, NULL);
174#elif defined _WIN32
175        WaitForSingleObject(m_thread, INFINITE);
176#endif
177    }
178
179private:
180#if defined __linux__ || defined __native_client__
181    pthread_t m_thread;
182#elif defined _WIN32
183    HANDLE m_thread;
184    DWORD m_tid;
185#endif
186};
187
188} /* namespace lol */
189
190#endif // __LOL_THREADBASE_H__
191
Note: See TracBrowser for help on using the repository browser.