2
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
3
* Copyright 2008-2010 Pelican Mapping
6
* osgEarth is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>
19
#ifndef OSGEARTH_THREADING_UTILS_H
20
#define OSGEARTH_THREADING_UTILS_H 1
22
#include <osgEarth/Common>
23
#include <OpenThreads/Condition>
24
#include <OpenThreads/Mutex>
27
#define USE_CUSTOM_READ_WRITE_LOCK 1
29
//# define TRACE_THREADS 1
32
namespace osgEarth { namespace Threading
34
typedef OpenThreads::Mutex Mutex;
35
typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedMutexLock;
37
#ifdef USE_CUSTOM_READ_WRITE_LOCK
40
* Event with a toggled signal state.
45
Event() : _set( false ) { }
49
for( int i=0; i<255; ++i ) // workaround buggy broadcast
54
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
55
return _set ? true : (_cond.wait( &_m ) == 0);
59
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
62
_cond.broadcast(); // possible deadlock before OSG r10457 on windows
68
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
72
inline bool isSet() const {
77
OpenThreads::Mutex _m;
78
OpenThreads::Condition _cond;
84
* Custom read/write lock. The read/write lock in OSG can unlock mutexes from a different
85
* thread than the one that locked them - this can hang the thread in Windows.
88
* http://www.codeproject.com/KB/threads/ReadWriteLock.aspx
93
typedef std::set<OpenThreads::Thread*> TracedThreads;
95
OpenThreads::Mutex _traceMutex;
102
_noWriterEvent.set();
103
_noReadersEvent.set();
111
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
112
if( _trace.find(OpenThreads::Thread::CurrentThread()) != _trace.end() )
113
OE_WARN << "TRACE: tried to double-lock" << std::endl;
118
_noWriterEvent.wait(); // wait for a writer to quit if there is one
119
incrementReaderCount(); // register this reader
120
if ( !_noWriterEvent.isSet() ) // double lock check, in case a writer snuck in while inrementing
121
decrementReaderCount(); // if it did, undo the registration and try again
123
break; // otherwise, we're in
128
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
129
_trace.insert(OpenThreads::Thread::CurrentThread());
136
decrementReaderCount(); // unregister this reader
140
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
141
_trace.erase(OpenThreads::Thread::CurrentThread());
150
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
151
if( _trace.find(OpenThreads::Thread::CurrentThread()) != _trace.end() )
152
OE_WARN << "TRACE: tried to double-lock" << std::endl;
155
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _lockWriterMutex ); // one at a time please
156
_noWriterEvent.wait(); // wait for a writer to quit if there is one
157
_noWriterEvent.reset(); // prevent further writers from joining
158
_noReadersEvent.wait(); // wait for all readers to quit
162
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
163
_trace.insert(OpenThreads::Thread::CurrentThread());
170
_noWriterEvent.set();
174
OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
175
_trace.erase(OpenThreads::Thread::CurrentThread());
182
void incrementReaderCount()
184
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _readerCountMutex );
185
_readerCount++; // add a reader
186
_noReadersEvent.reset(); // there's at least one reader now so clear the flag
189
void decrementReaderCount()
191
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _readerCountMutex );
192
_readerCount--; // remove a reader
193
if ( _readerCount <= 0 ) // if that was the last one, signal that writers are now allowed
194
_noReadersEvent.set();
199
OpenThreads::Mutex _lockWriterMutex;
200
OpenThreads::Mutex _readerCountMutex;
201
Event _noWriterEvent;
202
Event _noReadersEvent;
206
struct ScopedWriteLock
208
ScopedWriteLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.writeLock(); }
209
~ScopedWriteLock() { _lock.writeUnlock(); }
211
ReadWriteMutex& _lock;
214
struct ScopedReadLock
216
ScopedReadLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.readLock(); }
217
~ScopedReadLock() { _lock.readUnlock(); }
219
ReadWriteMutex& _lock;
224
typedef OpenThreads::ReadWriteMutex ReadWriteMutex;
225
typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
226
typedef OpenThreads::ScopedReadLock ScopedReadLock;
230
} } // namepsace osgEarth::Threading
233
#endif // OSGEARTH_THREADING_UTILS_H