~ubuntu-branches/debian/sid/osgearth/sid

« back to all changes in this revision

Viewing changes to src/osgEarth/ThreadingUtils

  • Committer: Bazaar Package Importer
  • Author(s): Pirmin Kalberer
  • Date: 2011-07-14 22:13:36 UTC
  • Revision ID: james.westby@ubuntu.com-20110714221336-94igk9rskxveh794
Tags: upstream-2.0+dfsg
ImportĀ upstreamĀ versionĀ 2.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*-c++-*- */
 
2
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 
3
 * Copyright 2008-2010 Pelican Mapping
 
4
 * http://osgearth.org
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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/>
 
18
 */
 
19
#ifndef OSGEARTH_THREADING_UTILS_H
 
20
#define OSGEARTH_THREADING_UTILS_H 1
 
21
 
 
22
#include <osgEarth/Common>
 
23
#include <OpenThreads/Condition>
 
24
#include <OpenThreads/Mutex>
 
25
#include <set>
 
26
 
 
27
#define USE_CUSTOM_READ_WRITE_LOCK 1
 
28
//#ifdef _DEBUG
 
29
//#  define TRACE_THREADS 1
 
30
//#endif
 
31
 
 
32
namespace osgEarth { namespace Threading
 
33
{   
 
34
    typedef OpenThreads::Mutex Mutex;
 
35
    typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedMutexLock;
 
36
 
 
37
#ifdef USE_CUSTOM_READ_WRITE_LOCK
 
38
 
 
39
    /**
 
40
     * Event with a toggled signal state.
 
41
     */
 
42
    class Event 
 
43
    {
 
44
    public:
 
45
        Event() : _set( false ) { }
 
46
 
 
47
        ~Event() { 
 
48
            reset(); 
 
49
            for( int i=0; i<255; ++i ) // workaround buggy broadcast
 
50
                _cond.signal();
 
51
        }
 
52
 
 
53
        inline bool wait() {
 
54
            OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
 
55
            return _set ? true : (_cond.wait( &_m ) == 0);
 
56
        }
 
57
 
 
58
        inline void set() {
 
59
            OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
 
60
            if ( !_set ) {
 
61
                _set = true;
 
62
                _cond.broadcast(); // possible deadlock before OSG r10457 on windows
 
63
                //_cond.signal();
 
64
            }
 
65
        }
 
66
 
 
67
        inline void reset() {
 
68
            OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _m );
 
69
            _set = false;
 
70
        }
 
71
 
 
72
        inline bool isSet() const {
 
73
            return _set;
 
74
        }
 
75
 
 
76
    protected:
 
77
        OpenThreads::Mutex _m;
 
78
        OpenThreads::Condition _cond;
 
79
        bool _set;
 
80
    };
 
81
 
 
82
 
 
83
    /**
 
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.
 
86
     *
 
87
     * Adapted from:
 
88
     * http://www.codeproject.com/KB/threads/ReadWriteLock.aspx
 
89
     */
 
90
    class ReadWriteMutex
 
91
    {
 
92
#if TRACE_THREADS
 
93
        typedef std::set<OpenThreads::Thread*> TracedThreads;
 
94
        TracedThreads _trace;
 
95
        OpenThreads::Mutex _traceMutex;
 
96
#endif
 
97
 
 
98
    public:
 
99
        ReadWriteMutex() :
 
100
          _readerCount(0)
 
101
        { 
 
102
            _noWriterEvent.set();
 
103
            _noReadersEvent.set();
 
104
        }
 
105
 
 
106
        void readLock()
 
107
        {
 
108
 
 
109
#ifdef TRACE_THREADS
 
110
            {
 
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;
 
114
            }
 
115
#endif
 
116
            for( ; ; )
 
117
            {
 
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
 
122
                else
 
123
                    break;                         // otherwise, we're in
 
124
            }
 
125
 
 
126
#ifdef TRACE_THREADS
 
127
            {
 
128
                OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
 
129
                _trace.insert(OpenThreads::Thread::CurrentThread());
 
130
            }
 
131
#endif
 
132
        }
 
133
 
 
134
        void readUnlock()
 
135
        {
 
136
            decrementReaderCount();                // unregister this reader
 
137
            
 
138
#ifdef TRACE_THREADS
 
139
            {
 
140
                OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
 
141
                _trace.erase(OpenThreads::Thread::CurrentThread());
 
142
            }
 
143
#endif
 
144
        }
 
145
 
 
146
        void writeLock()
 
147
        {
 
148
#ifdef TRACE_THREADS
 
149
            {
 
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;
 
153
            }
 
154
#endif
 
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
 
159
 
 
160
#ifdef TRACE_THREADS
 
161
            {
 
162
                OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
 
163
                _trace.insert(OpenThreads::Thread::CurrentThread());
 
164
            }
 
165
#endif
 
166
        }
 
167
 
 
168
        void writeUnlock()
 
169
        {
 
170
            _noWriterEvent.set();
 
171
 
 
172
#ifdef TRACE_THREADS
 
173
            {
 
174
                OpenThreads::ScopedLock<OpenThreads::Mutex> ttLock(_traceMutex);
 
175
                _trace.erase(OpenThreads::Thread::CurrentThread());
 
176
            }
 
177
#endif
 
178
        }
 
179
 
 
180
    protected:
 
181
 
 
182
        void incrementReaderCount()
 
183
        {
 
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
 
187
        }
 
188
 
 
189
        void decrementReaderCount()
 
190
        {
 
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();
 
195
        }
 
196
 
 
197
    private:
 
198
        int _readerCount;
 
199
        OpenThreads::Mutex _lockWriterMutex;
 
200
        OpenThreads::Mutex _readerCountMutex;
 
201
        Event _noWriterEvent;
 
202
        Event _noReadersEvent;
 
203
    };
 
204
 
 
205
 
 
206
    struct ScopedWriteLock
 
207
    {
 
208
        ScopedWriteLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.writeLock(); }
 
209
        ~ScopedWriteLock() { _lock.writeUnlock(); }
 
210
    protected:
 
211
        ReadWriteMutex& _lock;
 
212
    };
 
213
 
 
214
    struct ScopedReadLock
 
215
    {
 
216
        ScopedReadLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.readLock(); }
 
217
        ~ScopedReadLock() { _lock.readUnlock(); }
 
218
    protected:
 
219
        ReadWriteMutex& _lock;
 
220
    };
 
221
 
 
222
#else
 
223
 
 
224
    typedef OpenThreads::ReadWriteMutex  ReadWriteMutex;
 
225
    typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
 
226
    typedef OpenThreads::ScopedReadLock  ScopedReadLock;
 
227
 
 
228
#endif
 
229
 
 
230
} } // namepsace osgEarth::Threading
 
231
 
 
232
 
 
233
#endif // OSGEARTH_THREADING_UTILS_H
 
234