/usr/include/osgEarth/ThreadingUtils is in libosgearth-dev 2.9.0+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | /* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2016 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_THREADING_UTILS_H
#define OSGEARTH_THREADING_UTILS_H 1
#include <osgEarth/Common>
#include <OpenThreads/Condition>
#include <OpenThreads/Mutex>
#include <OpenThreads/Thread>
#include <osg/ref_ptr>
#include <set>
#include <map>
#define USE_CUSTOM_READ_WRITE_LOCK 1
namespace osgEarth { namespace Threading
{
typedef OpenThreads::Mutex Mutex;
typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedMutexLock;
typedef OpenThreads::Thread Thread;
/**
* Gets the unique ID of the running thread. Use this instead of
* OpenThreads::Thread::CurrentThread, which only works reliably on
* threads created with the OpenThreads framework
*/
extern OSGEARTH_EXPORT unsigned getCurrentThreadId();
/**
* Event with a binary signaled state, for multi-threaded sychronization.
*
* The event has two states:
* "set" means that a call to wait() will not block;
* "unset" means that calls to wait() will block until another thread calls set().
*
* The event starts out unset.
*
* Typical usage: Thread A creates Thread B to run asynchronous code. Thread A
* then calls wait(), which blocks Thread A. When Thread B is finished, it calls
* set(). Thread A then wakes up and continues execution.
*/
class OSGEARTH_EXPORT Event
{
public:
//! Construct a new event
Event();
//! DTOR
~Event();
//! Block until the event is set, then return true if set, false on error.
bool wait();
//! Like wait(), but also returns false on timeout.
bool wait(unsigned timeout_ms);
//! Like wait(), but resets the state before returning.
bool waitAndReset();
//! Set the event state, causing any waiters to unblock.
void set();
//! Reset (unset) the event state; new waiters will block until set() is called.
void reset();
//! Whether the event state is set (waiters will not block).
inline bool isSet() const { return _set; }
protected:
OpenThreads::Mutex _m;
OpenThreads::Condition _cond;
bool _set;
};
/** Wraps an Event in a Referenced. */
class OSGEARTH_EXPORT RefEvent : public Event, public osg::Referenced
{
};
/**
* Same as Event, but set() must be called N times before unblocking
* waiting thread(s).
*/
class OSGEARTH_EXPORT MultiEvent
{
public:
//! Construct a multi-event with the number of setters.
MultiEvent(int num =1);
//! DTOR
~MultiEvent();
//! Block the calling thread until all N set()s are called.
bool wait();
//! Same as wait(), but resets the state after returning.
bool waitAndReset();
//! Adds one signal to the event; when all signals are set, waiters will unblock.
void set();
void notify() { set(); }
//! Resets the state.
void reset();
protected:
OpenThreads::Mutex _m;
OpenThreads::Condition _cond;
int _set, _num;
};
/**
* Future is the consumer-side interface to an asynchronous operation.
*
* Usage:
* Producer (usually an asynchronous function call) creates a Promise<Object>
* and immediately returns promise.getFuture(). The Consumer then performs other
* work, and eventually (or immediately) called Future.get() or Future.release().
* Either call will block until the asynchronous operation is complete and the
* result in Future is available.
*/
template<typename T>
class Future
{
private:
// internal structure to track referenced to the result
struct RefPtrRef : public osg::Referenced {
RefPtrRef(T* obj = 0L) : _obj(obj) { }
osg::ref_ptr<T> _obj;
};
public:
//! Blank CTOR
Future() {
_ev = new RefEvent();
_objRef = new RefPtrRef();
}
//! Copy CTOR
Future(const Future& rhs) : _ev(rhs._ev), _objRef(rhs._objRef.get()) { }
//! True if the promise was resolved and a result if available.
bool isAvailable() const {
return _ev->isSet();
}
//! True if the Promise that generated this Future no longer exists.
bool isAbandoned() const {
return _objRef->referenceCount() == 1;
}
//! The result value; blocks until it is available (or abandonded) and then returns it.
T* get() {
while(!_ev->wait(1000u))
if (isAbandoned()) return 0L;
return _objRef->_obj.get();
}
//! The result value; blocks until available (or abandoned) and returns it; then resets to initial state.
T* release() {
while(!_ev->wait(1000u))
if (isAbandoned()) return 0L;
T* out = _objRef->_obj.release();
_ev->reset();
return out;
}
private:
osg::ref_ptr<RefEvent> _ev;
osg::ref_ptr<RefPtrRef> _objRef;
template<typename U> friend class Promise;
};
/**
* Promise is the producer-side interface to an asynchronous operation.
*
* Usage: The code that initiates an asychronous operation creates a Promise
* object, dispatches the asynchronous code, and immediately returns
* Promise.getFuture(). The caller can then call future.get() to block until
* the result is available.
*/
template<typename T>
class Promise
{
public:
//! This promise's future result.
const Future<T> getFuture() const { return _future; }
//! Resolve (fulfill) the promise with the provided result value.
void resolve(T* value) {
_future._objRef->_obj = value;
_future._ev->set();
}
//! True if the promise is resolved and the Future holds a valid result.
bool isResolved() const {
return _future._ev->isSet();
}
//! True is there are no Future objects waiting on this Promise.
bool isAbandoned() const {
return _future._objRef->referenceCount() == 1;
}
private:
Future<T> _future;
};
#ifdef USE_CUSTOM_READ_WRITE_LOCK
/**
* Custom read/write lock. The read/write lock in OSG can unlock mutexes from a different
* thread than the one that locked them - this can hang the thread in Windows.
*
* Adapted from:
* http://www.codeproject.com/KB/threads/ReadWriteLock.aspx
*/
class OSGEARTH_EXPORT ReadWriteMutex
{
public:
//! Construct a read/write mutex.
ReadWriteMutex();
//! Lock for reading. Multiple threads can take a read lock simultaneously.
void readLock();
//! Unlock for reading.
void readUnlock();
//! Lock for writing. This is exclusive; no other read OR write locks may be taken.
void writeLock();
//! Release a write lock.
void writeUnlock();
protected:
void incrementReaderCount();
void decrementReaderCount();
private:
int _readerCount;
Mutex _lockWriterMutex;
Mutex _readerCountMutex;
Event _noWriterEvent;
Event _noReadersEvent;
};
struct ScopedWriteLock
{
ScopedWriteLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.writeLock(); }
~ScopedWriteLock() { _lock.writeUnlock(); }
protected:
ReadWriteMutex& _lock;
};
struct ScopedReadLock
{
ScopedReadLock( ReadWriteMutex& lock ) : _lock(lock) { _lock.readLock(); }
~ScopedReadLock() { _lock.readUnlock(); }
protected:
ReadWriteMutex& _lock;
};
#else
typedef OpenThreads::ReadWriteMutex ReadWriteMutex;
typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
typedef OpenThreads::ScopedReadLock ScopedReadLock;
#endif
} } // namepsace osgEarth::Threading
#endif // OSGEARTH_THREADING_UTILS_H
|