#pragma once #include #include class rw_lock { private: volatile long m_requests, m_completions; static long atomic_clear_add(volatile long *dest, long clrmask, long val) { long cmp, exch, oldval = *dest; do { cmp = oldval; exch = (oldval & ~clrmask) + val; } while((oldval = _InterlockedCompareExchange(dest, exch, cmp)) != cmp); return oldval; } static void sleep_heuristic(unsigned int tries) { if(tries < 1000) { #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 SwitchToThread(); #else Sleep(0); #endif } else Sleep((tries < 2000) ? 100 : 1000); } public: rw_lock() : m_requests(0),m_completions(0) {} class scoped_read_lock { private: rw_lock &m_lock; bool m_locked; public: scoped_read_lock(rw_lock &m, bool lock = true) : m_lock(m),m_locked(false) { if(lock) this->lock(); } ~scoped_read_lock() { if(m_locked) this->unlock(); } void lock() { if(m_locked) return; unsigned int ticket = atomic_clear_add(&m_lock.m_requests, 0x80000000, 0x10000) & 0xffff; unsigned int tries = 0; while((m_lock.m_completions & 0xffff) != ticket) { sleep_heuristic(++tries); } m_locked = true; } void unlock() { if(!m_locked) return; atomic_clear_add(&m_lock.m_completions, 0x80000000, 0x10000); m_locked = false; } bool locked() const { return m_locked; } }; class scoped_write_lock { private: rw_lock &m_lock; bool m_locked; public: scoped_write_lock(rw_lock &m, bool lock = true) : m_lock(m),m_locked(false) { if(lock) this->lock(); } ~scoped_write_lock() { if(m_locked) this->unlock(); } void lock() { if(m_locked) return; unsigned int ticket = atomic_clear_add(&m_lock.m_requests, 0x8000, 1); unsigned int tries = 0; while(m_lock.m_completions != ticket) { sleep_heuristic(++tries); } m_locked = true; } void unlock() { if(!m_locked) return; atomic_clear_add(&m_lock.m_completions, 0x8000, 1); m_locked = false; } bool locked() const { return m_locked; } }; };