From c83f8e243463554ecf3a91e45d3e0b3b9c11895c Mon Sep 17 00:00:00 2001 From: Guenter Obiltschnig Date: Wed, 17 Sep 2008 19:13:50 +0000 Subject: [PATCH] fixed SF# 1896482: tryReadLock intermittent error --- Foundation/include/Poco/RWLock_WIN32.h | 3 ++- Foundation/src/RWLock_WIN32.cpp | 21 ++++++++++++++------- Foundation/testsuite/src/RWLockTest.cpp | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Foundation/include/Poco/RWLock_WIN32.h b/Foundation/include/Poco/RWLock_WIN32.h index 2572a3646..7345ec5a7 100644 --- a/Foundation/include/Poco/RWLock_WIN32.h +++ b/Foundation/include/Poco/RWLock_WIN32.h @@ -1,7 +1,7 @@ // // RWLock_WIN32.h // -// $Id: //poco/svn/Foundation/include/Poco/RWLock_WIN32.h#2 $ +// $Id: //poco/1.3/Foundation/include/Poco/RWLock_WIN32.h#3 $ // // Library: Foundation // Package: Threading @@ -67,6 +67,7 @@ private: HANDLE _readEvent; HANDLE _writeEvent; unsigned _readers; + unsigned _writersWaiting; unsigned _writers; }; diff --git a/Foundation/src/RWLock_WIN32.cpp b/Foundation/src/RWLock_WIN32.cpp index f28a2411d..6a3296470 100644 --- a/Foundation/src/RWLock_WIN32.cpp +++ b/Foundation/src/RWLock_WIN32.cpp @@ -1,7 +1,7 @@ // // RWLock_WIN32.cpp // -// $Id: //poco/svn/Foundation/src/RWLock_WIN32.cpp#2 $ +// $Id: //poco/1.3/Foundation/src/RWLock_WIN32.cpp#3 $ // // Library: Foundation // Package: Threading @@ -40,7 +40,7 @@ namespace Poco { -RWLockImpl::RWLockImpl(): _readers(0), _writers(0) +RWLockImpl::RWLockImpl(): _readers(0), _writersWaiting(0), _writers(0) { _mutex = CreateMutexW(NULL, FALSE, NULL); if (_mutex == NULL) @@ -69,7 +69,7 @@ inline void RWLockImpl::addWriter() switch (WaitForSingleObject(_mutex, INFINITE)) { case WAIT_OBJECT_0: - if (++_writers == 1) ResetEvent(_readEvent); + if (++_writersWaiting == 1) ResetEvent(_readEvent); ReleaseMutex(_mutex); break; default: @@ -83,7 +83,7 @@ inline void RWLockImpl::removeWriter() switch (WaitForSingleObject(_mutex, INFINITE)) { case WAIT_OBJECT_0: - if (--_writers == 0) SetEvent(_readEvent); + if (--_writersWaiting == 0 && _writers == 0) SetEvent(_readEvent); ReleaseMutex(_mutex); break; default: @@ -104,6 +104,7 @@ void RWLockImpl::readLockImpl() ++_readers; ResetEvent(_writeEvent); ReleaseMutex(_mutex); + poco_assert_dbg(_writers == 0); break; default: throw SystemException("cannot lock reader/writer lock"); @@ -123,6 +124,7 @@ bool RWLockImpl::tryReadLockImpl() ++_readers; ResetEvent(_writeEvent); ReleaseMutex(_mutex); + poco_assert_dbg(_writers == 0); return true; case WAIT_TIMEOUT: return false; @@ -142,11 +144,13 @@ void RWLockImpl::writeLockImpl() { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: - --_writers; + --_writersWaiting; ++_readers; + ++_writers; ResetEvent(_readEvent); ResetEvent(_writeEvent); ReleaseMutex(_mutex); + poco_assert_dbg(_writers == 1); break; default: removeWriter(); @@ -165,11 +169,13 @@ bool RWLockImpl::tryWriteLockImpl() { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: - --_writers; + --_writersWaiting; ++_readers; + ++_writers; ResetEvent(_readEvent); ResetEvent(_writeEvent); ReleaseMutex(_mutex); + poco_assert_dbg(_writers == 1); return true; case WAIT_TIMEOUT: removeWriter(); @@ -186,7 +192,8 @@ void RWLockImpl::unlockImpl() switch (WaitForSingleObject(_mutex, INFINITE)) { case WAIT_OBJECT_0: - if (_writers == 0) SetEvent(_readEvent); + _writers = 0; + if (_writersWaiting == 0) SetEvent(_readEvent); if (--_readers == 0) SetEvent(_writeEvent); ReleaseMutex(_mutex); break; diff --git a/Foundation/testsuite/src/RWLockTest.cpp b/Foundation/testsuite/src/RWLockTest.cpp index 28873a2df..5c5e1d082 100644 --- a/Foundation/testsuite/src/RWLockTest.cpp +++ b/Foundation/testsuite/src/RWLockTest.cpp @@ -1,7 +1,7 @@ // // RWLockTest.cpp // -// $Id: //poco/svn/Foundation/testsuite/src/RWLockTest.cpp#2 $ +// $Id: //poco/1.3/Foundation/testsuite/src/RWLockTest.cpp#2 $ // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -60,13 +60,20 @@ public: for (int k = 0; k < 100; ++k) { if (_counter != lastCount) _ok = false; + Thread::yield(); } _lock.unlock(); _lock.writeLock(); for (int k = 0; k < 100; ++k) + { --_counter; + Thread::yield(); + } for (int k = 0; k < 100; ++k) + { ++_counter; + Thread::yield(); + } ++_counter; if (_counter <= lastCount) _ok = false; _lock.unlock(); @@ -102,13 +109,20 @@ public: for (int k = 0; k < 100; ++k) { if (_counter != lastCount) _ok = false; + Thread::yield(); } _lock.unlock(); while (!_lock.tryWriteLock()) Thread::yield(); for (int k = 0; k < 100; ++k) + { --_counter; + Thread::yield(); + } for (int k = 0; k < 100; ++k) + { ++_counter; + Thread::yield(); + } ++_counter; if (_counter <= lastCount) _ok = false; _lock.unlock();