#include "Critical.h" #include #include #include "Globals.h" #include "Thread.h" using namespace Framework; // Content of the Critical class from Critical.h // Konstructor Critical::Critical() { InitializeCriticalSection(&cs); lockCount = 0; } // Destructor Critical::~Critical() { DeleteCriticalSection(&cs); } // locks the object void Critical::lock() { currentThreadLockCount++; EnterCriticalSection(&cs); lockCount++; } // tries to lock the object bool Critical::tryLock() { if (lockCount > 0) return false; currentThreadLockCount++; EnterCriticalSection(&cs); lockCount++; return true; } // unlocks the object void Critical::unlock() { if (lockCount <= 0) { throw "A Thread tried to unlock a critical that was not locked before"; } lockCount--; LeaveCriticalSection(&cs); currentThreadLockCount--; } // returns true if the object is locked bool Critical::isLocked() const { return lockCount > 0; } Synchronizer::Synchronizer() : numWaiting(0), skip(0) {} Synchronizer::~Synchronizer() { skip = 1; std::unique_lock lk(mutex); if (numWaiting > 0) { lk.unlock(); block.notify_all(); } else lk.unlock(); while (numWaiting > 0) Sleep(10); lk.lock(); } bool Synchronizer::wait() { std::unique_lock lk(mutex); if (skip) return false; numWaiting++; block.wait(lk); numWaiting--; return !skip; } bool Synchronizer::wait(int milisec) { std::unique_lock lk(mutex); if (skip) return false; numWaiting++; std::cv_status status = block.wait_for(lk, std::chrono::milliseconds(milisec)); numWaiting--; return !skip && status == std::cv_status::no_timeout; } void Synchronizer::notify() { block.notify_one(); } void Synchronizer::notify(int amount) { while (amount--) block.notify_one(); } void Synchronizer::notifyAll() { block.notify_all(); } int Synchronizer::getNumberOfWaitingThreads() const { return numWaiting; } Framework::StackLock::StackLock(std::initializer_list locks) { this->locks = new Lock*[locks.size()]; int i = 0; for (Lock* c : locks) { this->locks[i] = c; i++; } size = (int)locks.size(); if (size > 0) { this->locks[0]->lock(); int index = 1; while (index < size) { if (!this->locks[index]->tryLock()) { for (int i = 0; i < index; i++) { this->locks[i]->unlock(); } this->locks[index]->lock(); this->locks[index]->unlock(); this->locks[0]->lock(); index = 1; } else index++; } } } Framework::StackLock::~StackLock() { for (int i = 0; i < size; i++) { locks[i]->unlock(); } delete[] locks; } class Framework::InternalReadLock : public Lock { private: ReadWriteLock* rwLock; public: InternalReadLock(ReadWriteLock* rwLock) : rwLock(rwLock) {} virtual ~InternalReadLock() = default; void lock() override { rwLock->lockRead(); } void unlock() override { rwLock->unlockRead(); } bool tryLock() override { return rwLock->tryLockRead(); } }; class Framework::InternalWriteLock : public Lock { private: ReadWriteLock* rwLock; public: InternalWriteLock(ReadWriteLock* rwLock) : rwLock(rwLock) {} virtual ~InternalWriteLock() = default; void lock() override { rwLock->lockWrite(); } void unlock() override { rwLock->unlockWrite(); } bool tryLock() override { return rwLock->tryLockWrite(); } }; Framework::ReadWriteLock::ReadWriteLock(int initialMaxSize) : readerThreads(new int[initialMaxSize]), readCounters(new int[initialMaxSize]), maxSize(initialMaxSize), readerThreadCount(0), writerThread(0), writerCount(0), waitingReaders(0), waitingWriters(0), readLock(new InternalReadLock(this)), writeLock(new InternalWriteLock(this)) { memset(readerThreads, 0, sizeof(int) * initialMaxSize); memset(readCounters, 0, sizeof(int) * initialMaxSize); } Framework::ReadWriteLock::~ReadWriteLock() { delete[] readerThreads; delete[] readCounters; delete readLock; delete writeLock; } void Framework::ReadWriteLock::lockRead() { cs.lock(); while (writerCount > 0 && writerThread != currentThreadId) { waitingReaders++; cs.unlock(); readerBlock.wait(); cs.lock(); waitingReaders--; } currentThreadLockCount++; int index = -1; for (int i = 0; i < readerThreadCount; i++) { if (readerThreads[i] == currentThreadId) { index = i; break; } } if (index == -1) { if (readerThreadCount == maxSize) { int* newReaderThreads = new int[maxSize * 2]; int* newReadCounters = new int[maxSize * 2]; for (int i = 0; i < maxSize; i++) { newReaderThreads[i] = readerThreads[i]; newReadCounters[i] = readCounters[i]; } delete[] readerThreads; delete[] readCounters; readerThreads = newReaderThreads; readCounters = newReadCounters; maxSize *= 2; } index = readerThreadCount++; readerThreads[index] = currentThreadId; } readCounters[index]++; cs.unlock(); } void Framework::ReadWriteLock::lockWrite() { cs.lock(); while ( (writerCount > 0 && writerThread != currentThreadId) || (readerThreadCount > 0 && (readerThreadCount != 1 || readerThreads[0] != currentThreadId))) { waitingWriters++; cs.unlock(); writerBlock.wait(); cs.lock(); waitingWriters--; } currentThreadLockCount++; writerThread = currentThreadId; writerCount++; cs.unlock(); } void Framework::ReadWriteLock::unlockRead() { cs.lock(); int index = -1; for (int i = 0; i < readerThreadCount; i++) { if (readerThreads[i] == currentThreadId) { index = i; break; } } if (index == -1 || readCounters[index] == 0) { cs.unlock(); throw "A Thread that does not hold a read lock tries to unlock it"; } readCounters[index]--; if (readCounters[index] == 0) { readerThreads[index] = readerThreads[readerThreadCount - 1]; readCounters[index] = readCounters[readerThreadCount - 1]; readerThreadCount--; } if (readerThreadCount == 0 && waitingWriters > 0) { writerBlock.notify(); } currentThreadLockCount--; cs.unlock(); } void Framework::ReadWriteLock::unlockWrite() { cs.lock(); if (writerThread != currentThreadId || writerCount == 0) { cs.unlock(); throw "A Thread that does not hold the write lock tries to unlock it"; } writerCount--; if (writerCount == 0) { if (waitingWriters > 0) { writerBlock.notify(); } else if (waitingReaders > 0) { readerBlock.notify(waitingReaders); } } currentThreadLockCount--; cs.unlock(); } bool Framework::ReadWriteLock::tryLockRead() { cs.lock(); if (writerCount > 0 && writerThread != currentThreadId) { cs.unlock(); return false; } currentThreadLockCount++; int index = -1; for (int i = 0; i < readerThreadCount; i++) { if (readerThreads[i] == currentThreadId) { index = i; break; } } if (index == -1) { if (readerThreadCount == maxSize) { int* newReaderThreads = new int[maxSize * 2]; int* newReadCounters = new int[maxSize * 2]; for (int i = 0; i < maxSize; i++) { newReaderThreads[i] = readerThreads[i]; newReadCounters[i] = readCounters[i]; } delete[] readerThreads; delete[] readCounters; readerThreads = newReaderThreads; readCounters = newReadCounters; maxSize *= 2; } index = readerThreadCount++; readerThreads[index] = currentThreadId; } readCounters[index]++; cs.unlock(); return true; } bool Framework::ReadWriteLock::tryLockWrite() { cs.lock(); if ((writerCount > 0 && writerThread != currentThreadId) || (readerThreadCount > 0 && (readerThreadCount != 1 || readerThreads[0] != currentThreadId))) { cs.unlock(); return false; } currentThreadLockCount++; writerThread = currentThreadId; writerCount++; cs.unlock(); return true; } Lock& Framework::ReadWriteLock::getReadLock() const { return *readLock; } Lock& Framework::ReadWriteLock::getWriteLock() const { return *writeLock; } int Framework::ReadWriteLock::getReadThreadCount() const { return readerThreadCount; } bool Framework::ReadWriteLock::isWriteLocked() const { return writerCount > 0; } int Framework::ReadWriteLock::getReadThread(int index) const { if (index < 0 || index >= readerThreadCount) { throw "Index out of bounds"; } return readerThreads[index]; } int Framework::ReadWriteLock::getWriteLockThread() const { return writerThread; } int Framework::ReadWriteLock::getWriteLockCount() const { return writerCount; } int Framework::ReadWriteLock::getReadLockCount(int threadId) const { for (int i = 0; i < readerThreadCount; i++) { if (readerThreads[i] == threadId) { return readCounters[i]; } } return 0; }