Library of Assembled Shared Sources
thread.cpp
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#include "lass_common.h"
44#include "thread.h"
45#include "atomic.h"
46
47#if LASS_HAVE_WIN32_THREADS
48# include "impl/thread_win32.inl"
49#elif LASS_HAVE_PTHREAD_H
50# include "impl/thread_posix.inl"
51#else
52# error "[LASS BUILD MSG] Threading not supported for this platform"
53#endif
54
55namespace lass
56{
57namespace util
58{
59
60const TCpuSet availableProcessors()
61{
62 static TCpuSet set; // static it here, for SIOF
63 static bool isInitialized = false;
64 if (!isInitialized)
65 {
66 set = impl::availableProcessors();
67 isInitialized = true;
68 }
69 return set;
70}
71
72static TCpuSet forceCalculationAtStartup = availableProcessors();
73
75{
76 return availableProcessors().size();
77}
78
80{
81 const TCpuSet& set = availableProcessors();
82 return static_cast<size_t>(std::count(set.begin(), set.end(), true));
83}
84
85bool isAvailableProcessor(size_t processor)
86{
87 const TCpuSet& set = availableProcessors();
88 return processor < set.size() && set[processor];
89}
90
91// --- Mutex ---------------------------------------------------------------------------------------
92
93Mutex::Mutex(void )
94{
95 pimpl_ = new impl::MutexInternal;
96}
97
98Mutex::~Mutex(void)
99{
100 LASS_ASSERT(pimpl_);
101 LASS_ASSERT(pimpl_->lockCount() == 0);
102 if (pimpl_->lockCount() > 0)
103 {
104 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
105 << "destroying a CriticalSection that still has "
106 << pimpl_->lockCount() << " locks." << std::endl;
107 }
108 delete pimpl_;
109 pimpl_ = 0;
110}
111
112void Mutex::lock()
113{
114 LASS_ASSERT(pimpl_);
115 pimpl_->lock();
116}
117
118LockResult Mutex::tryLock()
119{
120 LASS_ASSERT(pimpl_);
121 return pimpl_->tryLock();
122}
123
124void Mutex::unlock()
125{
126 LASS_ASSERT(pimpl_);
127 pimpl_->unlock();
128}
129
130bool Mutex::isLocked() const
131{
132 LASS_ASSERT(pimpl_);
133 return pimpl_->lockCount() > 0;
134}
135
136
137
138
139// --- CriticalSection -----------------------------------------------------------------------------
140
141CriticalSection::CriticalSection(void )
142{
143 pimpl_ = new impl::CriticalSectionInternal;
144}
145
146CriticalSection::~CriticalSection(void)
147{
148 LASS_ASSERT(pimpl_);
149 impl::CriticalSectionInternal* pimpl = static_cast<impl::CriticalSectionInternal*>(pimpl_);
150 LASS_ASSERT(pimpl->lockCount() == 0);
151 if (pimpl->lockCount() > 0)
152 {
153 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
154 << "destroying a CriticalSection that still has "
155 << pimpl->lockCount() << " locks." << std::endl;
156 }
157 delete pimpl;
158 pimpl_ = 0;
159}
160
161void CriticalSection::lock()
162{
163 LASS_ASSERT(pimpl_);
164 impl::CriticalSectionInternal* pimpl = static_cast<impl::CriticalSectionInternal*>(pimpl_);
165 pimpl->lock();
166}
167
168LockResult CriticalSection::tryLock()
169{
170 LASS_ASSERT(pimpl_);
171 impl::CriticalSectionInternal* pimpl = static_cast<impl::CriticalSectionInternal*>(pimpl_);
172 return pimpl->tryLock();
173}
174
175void CriticalSection::unlock()
176{
177 LASS_ASSERT(pimpl_);
178 impl::CriticalSectionInternal* pimpl = static_cast<impl::CriticalSectionInternal*>(pimpl_);
179 pimpl->unlock();
180}
181
182bool CriticalSection::isLocked() const
183{
184 LASS_ASSERT(pimpl_);
185 impl::CriticalSectionInternal* pimpl = static_cast<impl::CriticalSectionInternal*>(pimpl_);
186 return pimpl->lockCount() > 0;
187}
188
189
190
191// --- Condition -----------------------------------------------------------------------------------
192
193Condition::Condition(void)
194{
195 pimpl_ = new impl::ConditionInternal;
196}
197
198Condition::~Condition(void)
199{
200 delete pimpl_;
201 pimpl_ = 0;
202}
203
204void Condition::wait()
205{
206 LASS_ASSERT(pimpl_);
207 pimpl_->wait();
208}
209
210WaitResult Condition::wait(unsigned long iMilliSeconds)
211{
212 LASS_ASSERT(pimpl_);
213 return pimpl_->wait(iMilliSeconds);
214}
215
216void Condition::signal()
217{
218 LASS_ASSERT(pimpl_);
219 pimpl_->signal();
220}
221
222void Condition::broadcast()
223{
224 LASS_ASSERT(pimpl_);
225 pimpl_->broadcast();
226}
227
228
229
230// --- Thread --------------------------------------------------------------------------------------
231
232Thread::Thread(ThreadKind iKind, const char* name)
233{
234 pimpl_ = new impl::ThreadInternal(*this, iKind, name);
235}
236
237/** @warning The destructor will not join joinable threads first. You have to do it yourself.
238 * Why? Well, as long as the worker thread is executing doRun(), it needs the complete thread
239 * object. By the time we get in ~Thread(), the derived class is already destructed and the
240 * thread would now be acting on a half destructed object. That can't be good, can it?
241 * So make sure you call join() before the destructor is invoked.
242 */
244{
245 delete pimpl_;
246 pimpl_ = 0;
247}
248
249void Thread::run()
250{
251 LASS_ASSERT(pimpl_);
252 pimpl_->run();
253}
254
255void Thread::join()
256{
257 LASS_ASSERT(pimpl_);
258 pimpl_->join();
259}
260
261/** bind this thread to a processor (this as in this-pointer)
262 */
263void Thread::bind(size_t processor)
264{
265 LASS_ASSERT(pimpl_);
266 pimpl_->bind(processor);
267}
268
269const TCpuSet Thread::affinity() const
270{
271 LASS_ASSERT(pimpl_);
272 return pimpl_->affinity();
273}
274
275void Thread::sleep(unsigned long iMilliSeconds)
276{
277 impl::ThreadInternal::sleep(iMilliSeconds);
278}
279
280void Thread::yield()
281{
282 impl::ThreadInternal::yield();
283}
284
285/** bind current thread to a processor (current as in callee's context)
286 */
287void Thread::bindCurrent(size_t processor)
288{
289 impl::ThreadInternal::bindCurrent(processor);
290}
291
292
293
294// --- ThreadLocalStorage --------------------------------------------------------------------------
295
296ThreadLocalStorage::ThreadLocalStorage(void (*destructor)(void*))
297{
298 pimpl_ = new impl::ThreadLocalStorageInternal(destructor);
299}
300
301ThreadLocalStorage::~ThreadLocalStorage()
302{
303 delete pimpl_;
304 pimpl_ = 0;
305}
306
307void* ThreadLocalStorage::get() const
308{
309 LASS_ASSERT(pimpl_);
310 return pimpl_->get();
311}
312
313void ThreadLocalStorage::set(void* value)
314{
315 LASS_ASSERT(pimpl_);
316 pimpl_->set(value);
317}
318
319}
320}
321
322// EOF
static void bindCurrent(size_t processor)
bind current thread to a processor (current as in callee's context)
Definition thread.cpp:287
virtual ~Thread()
Definition thread.cpp:243
void bind(size_t processor)
bind this thread to a processor (this as in this-pointer)
Definition thread.cpp:263
ThreadKind
ThreadKind.
Definition thread.h:109
bool isAvailableProcessor(size_t processor)
Check whether a processor is avaialable.
Definition thread.cpp:85
size_t numberOfAvailableProcessors()
Return total number of processors in machine that are online.
Definition thread.cpp:79
LockResult
Return code for lock functions.
Definition thread.h:89
size_t numberOfProcessors()
Return highest id of processor + 1, in this machine.
Definition thread.cpp:74
WaitResult
Return code for wait functions.
Definition thread.h:99
general utility, debug facilities, ...
Library for Assembled Shared Sources.
Definition config.h:53