|
@@ -0,0 +1,297 @@
|
|
|
|
|
+#include "pch.h"
|
|
|
|
|
+
|
|
|
|
|
+#define NO_MAIN
|
|
|
|
|
+#include <AsynchronCall.h>
|
|
|
|
|
+#include <Critical.h>
|
|
|
|
|
+#include <Globals.h>
|
|
|
|
|
+
|
|
|
|
|
+#include "CppUnitTest.h"
|
|
|
|
|
+
|
|
|
|
|
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
|
|
|
|
+
|
|
|
|
|
+namespace FrameworkTests
|
|
|
|
|
+{
|
|
|
|
|
+ TEST_CLASS (ReadWriteLockTest)
|
|
|
|
|
+ {
|
|
|
|
|
+ public:
|
|
|
|
|
+ ReadWriteLockTest()
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::initFramework(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ~ReadWriteLockTest()
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::releaseFramework();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testLockRead)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 0,
|
|
|
|
|
+ L"The current threads lock holding count should be 0 at the "
|
|
|
|
|
+ L"beginning");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 0,
|
|
|
|
|
+ L"Initialized ReadWriteLock should not have any readers.");
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 1,
|
|
|
|
|
+ L"The current threads lock holding count should be 1 after "
|
|
|
|
|
+ L"lockRead() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 1,
|
|
|
|
|
+ L"ReadWriteLock should have exactly one reader after "
|
|
|
|
|
+ L"lockRead() was called.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadThread(0) == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread id is not present in reader threads after "
|
|
|
|
|
+ L"lockRead() was called");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadLockCount(Framework::getCurrentThreadId()) == 1,
|
|
|
|
|
+ L"Lock count should be 1 after lockRead() was called once");
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 2,
|
|
|
|
|
+ L"The current threads lock holding count should be 2 after "
|
|
|
|
|
+ L"lockRead() was called twice");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 1,
|
|
|
|
|
+ L"ReadWriteLock should have exactly one reader after "
|
|
|
|
|
+ L"lockRead() was called twice by the same thread.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadThread(0) == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread id is not present in reader threads after "
|
|
|
|
|
+ L"lockRead() was called twice by the same thread");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadLockCount(Framework::getCurrentThreadId()) == 2,
|
|
|
|
|
+ L"Lock count should be 1 after lockRead() was called twice");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testUnlockRead)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 1,
|
|
|
|
|
+ L"The current threads lock holding count should be 1 after "
|
|
|
|
|
+ L"lockRead() was called twice and unlockRead() once");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 1,
|
|
|
|
|
+ L"ReadWriteLock should have exactly one reader after "
|
|
|
|
|
+ L"lockRead() was called twice and unlockRead() once by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadThread(0) == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread id is not present in reader threads after "
|
|
|
|
|
+ L"lockRead() was called twice and unlockRead() once by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadLockCount(Framework::getCurrentThreadId()) == 1,
|
|
|
|
|
+ L"Lock count should be 1 after lockRead() was called twice and "
|
|
|
|
|
+ L"unlockRead() once by the same thread.");
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 0,
|
|
|
|
|
+ L"The current threads lock holding count should be 0 after "
|
|
|
|
|
+ L"lockRead() was called twice and unlockRead() twice");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 0,
|
|
|
|
|
+ L"ReadWriteLock should have 0 readers after "
|
|
|
|
|
+ L"lockRead() was called twice and unlockRead() twice by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 1,
|
|
|
|
|
+ L"ReadWriteLock should have exactly one reader after "
|
|
|
|
|
+ L"lockRead() was called 3 times and unlockRead() twice by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 0,
|
|
|
|
|
+ L"ReadWriteLock should have 0 readers after "
|
|
|
|
|
+ L"lockRead() was called 3 times and unlockRead() 3 times by "
|
|
|
|
|
+ L"the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testLockWrite)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 0,
|
|
|
|
|
+ L"The write lock count should be 0 at the beginning");
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 1,
|
|
|
|
|
+ L"The current threads lock holding count should be 1 after "
|
|
|
|
|
+ L"lockWrite() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 1,
|
|
|
|
|
+ L"write lock count should be 1 after "
|
|
|
|
|
+ L"lockWrite() was called.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getWriteLockThread() == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread should be the writer thread after "
|
|
|
|
|
+ L"lockWrite() was called");
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 2,
|
|
|
|
|
+ L"The current threads lock holding count should be 2 after "
|
|
|
|
|
+ L"lockWrite() was called twice");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 2,
|
|
|
|
|
+ L"write lock count should be 2 after "
|
|
|
|
|
+ L"lockWrite() was called twice");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getWriteLockThread() == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread should be the writer thread after "
|
|
|
|
|
+ L"lockWrite() was called twice");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testUnlockWrite)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 1,
|
|
|
|
|
+ L"The current threads lock holding count should be 1 after "
|
|
|
|
|
+ L"lockWrite() was called twice and unlockWrite() once");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 1,
|
|
|
|
|
+ L"write lock count should be one reader after "
|
|
|
|
|
+ L"lockWrite() was called twice and unlockWrite() once by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getWriteLockThread() == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread id should be the writer thread after "
|
|
|
|
|
+ L"lockWrite() was called twice and unlockWrite() once by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 0,
|
|
|
|
|
+ L"The current threads lock holding count should be 0 after "
|
|
|
|
|
+ L"lockWrite() was called twice and unlockWrite() twice");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 0,
|
|
|
|
|
+ L"write lock count should be 0 after "
|
|
|
|
|
+ L"lockWrite() was called twice and unlockWrite() twice by the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 1,
|
|
|
|
|
+ L"write lock count should be exactly one after "
|
|
|
|
|
+ L"lockWrite() was called 3 times and unlockWrite() twice by "
|
|
|
|
|
+ L"the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 0,
|
|
|
|
|
+ L"write lock count should be 0 after "
|
|
|
|
|
+ L"lockWrite() was called 3 times and unlockWrite() 3 times by "
|
|
|
|
|
+ L"the "
|
|
|
|
|
+ L"same thread.");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testUpgrade)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 2,
|
|
|
|
|
+ L"The current threads lock holding count should be 2 after "
|
|
|
|
|
+ L"lockRead() and lockWrite() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 1,
|
|
|
|
|
+ L"write lock count should be 1 after "
|
|
|
|
|
+ L"lockWrite() was called.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getWriteLockThread() == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread should be the writer thread after "
|
|
|
|
|
+ L"lockWrite() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 1,
|
|
|
|
|
+ L"ReadWriteLock should have exactly one reader after "
|
|
|
|
|
+ L"lockRead() was called.");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadThread(0) == Framework::getCurrentThreadId(),
|
|
|
|
|
+ L"Current thread id is not present in reader threads after "
|
|
|
|
|
+ L"lockRead() was called");
|
|
|
|
|
+ Assert::IsTrue(
|
|
|
|
|
+ lock.getReadLockCount(Framework::getCurrentThreadId()) == 1,
|
|
|
|
|
+ L"Lock count should be 1 after lockRead() was called once");
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ Assert::IsTrue(Framework::getCurrentThreadLockCount() == 0,
|
|
|
|
|
+ L"The current threads lock holding count should be 0 after "
|
|
|
|
|
+ L"lockRead() and lockWrite() and unlockWrite() and "
|
|
|
|
|
+ L"unlockRead() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getWriteLockCount() == 0,
|
|
|
|
|
+ L"write lock count should be 0 after "
|
|
|
|
|
+ L"lockWrite() and unlockWrite() was called");
|
|
|
|
|
+ Assert::IsTrue(lock.getReadThreadCount() == 0,
|
|
|
|
|
+ L"write lock count should be 0 after "
|
|
|
|
|
+ L"lockRead() and unlockRead() was called");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testReadMultithreading)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ bool finished = 0;
|
|
|
|
|
+ new Framework::AsynchronCall(
|
|
|
|
|
+ [&lock]() {
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ },
|
|
|
|
|
+ &finished);
|
|
|
|
|
+ while (!finished)
|
|
|
|
|
+ {
|
|
|
|
|
+ Sleep(10);
|
|
|
|
|
+ }
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testWriteMultithreading)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ bool finished = 0;
|
|
|
|
|
+ bool lockAvailable = 0;
|
|
|
|
|
+ new Framework::AsynchronCall(
|
|
|
|
|
+ [&lock, &lockAvailable]() {
|
|
|
|
|
+ lockAvailable = lock.tryLockWrite();
|
|
|
|
|
+ },
|
|
|
|
|
+ &finished);
|
|
|
|
|
+ while (!finished)
|
|
|
|
|
+ {
|
|
|
|
|
+ Sleep(10);
|
|
|
|
|
+ }
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ Assert::IsFalse(lockAvailable,
|
|
|
|
|
+ L"Write lock should not be available when another thread is "
|
|
|
|
|
+ L"using it");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testWriteReadMultithreading)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockWrite();
|
|
|
|
|
+ bool finished = 0;
|
|
|
|
|
+ bool lockAvailable = 0;
|
|
|
|
|
+ new Framework::AsynchronCall(
|
|
|
|
|
+ [&lock, &lockAvailable]() {
|
|
|
|
|
+ lockAvailable = lock.tryLockRead();
|
|
|
|
|
+ },
|
|
|
|
|
+ &finished);
|
|
|
|
|
+ while (!finished)
|
|
|
|
|
+ {
|
|
|
|
|
+ Sleep(10);
|
|
|
|
|
+ }
|
|
|
|
|
+ lock.unlockWrite();
|
|
|
|
|
+ Assert::IsFalse(lockAvailable,
|
|
|
|
|
+ L"Read lock should not be available when another thread is "
|
|
|
|
|
+ L"writing");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TEST_METHOD (testReadWriteMultithreading)
|
|
|
|
|
+ {
|
|
|
|
|
+ Framework::ReadWriteLock lock;
|
|
|
|
|
+ lock.lockRead();
|
|
|
|
|
+ bool finished = 0;
|
|
|
|
|
+ bool lockAvailable = 0;
|
|
|
|
|
+ new Framework::AsynchronCall(
|
|
|
|
|
+ [&lock, &lockAvailable]() {
|
|
|
|
|
+ lockAvailable = lock.tryLockWrite();
|
|
|
|
|
+ },
|
|
|
|
|
+ &finished);
|
|
|
|
|
+ while (!finished)
|
|
|
|
|
+ {
|
|
|
|
|
+ Sleep(10);
|
|
|
|
|
+ }
|
|
|
|
|
+ lock.unlockRead();
|
|
|
|
|
+ Assert::IsFalse(lockAvailable,
|
|
|
|
|
+ L"Write lock should not be available when another thread is "
|
|
|
|
|
+ L"reading");
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+} // namespace FrameworkTests
|