#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); owner = 0; lockCount = 0; id = (int)time(0); } // Destructor Critical::~Critical() { DeleteCriticalSection(&cs); } pthread_t CachedCurrentThread() { volatile thread_local static pthread_t t = GetCurrentThread(); return (pthread_t)t; } // locks the object void Critical::lock() { getThreadRegister()->lock(); Thread* tmp = getThreadRegister()->zThread(CachedCurrentThread()); if (tmp) tmp->addCriticalLock(); getThreadRegister()->unlock(); EnterCriticalSection(&cs); if (!owner) owner = tmp; lockCount++; } // tries to lock the object bool Critical::tryLock() { if (lockCount > 0) return false; getThreadRegister()->lock(); Thread* tmp = getThreadRegister()->zThread(CachedCurrentThread()); if (tmp) tmp->addCriticalLock(); getThreadRegister()->unlock(); EnterCriticalSection(&cs); if (!owner) owner = tmp; lockCount++; return true; } // unlocks the object void Critical::unlock() { getThreadRegister()->lock(); Thread* tmp = 0; if (getThreadRegister()->isThread(owner)) { if (owner && GetThreadId(owner->getThreadHandle()) != GetThreadId(CachedCurrentThread())) throw std::runtime_error("A Thread that does not own a Critical " "Object trys to unlock it"); tmp = owner; } getThreadRegister()->unlock(); if (!--lockCount) owner = 0; LeaveCriticalSection(&cs); getThreadRegister()->lock(); if (tmp && getThreadRegister()->isThread(tmp)) tmp->removeCriticalLock(); getThreadRegister()->unlock(); } // returns true if the object is locked bool Critical::isLocked() const { return lockCount > 0; } // returns a pointer to the thread that locked the object const Thread* Critical::zOwner() const { return owner; } 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::CriticalLock::CriticalLock( std::initializer_list criticals) { this->criticals = new Critical*[criticals.size()]; int i = 0; for (Critical* c : criticals) { this->criticals[i] = c; i++; } size = (int)criticals.size(); if (size > 0) { this->criticals[0]->lock(); int index = 1; while (index < size) { if (!this->criticals[index]->tryLock()) { for (int i = 0; i < index; i++) { this->criticals[i]->unlock(); } this->criticals[index]->lock(); this->criticals[index]->unlock(); this->criticals[0]->lock(); index = 1; } else index++; } } } Framework::CriticalLock::~CriticalLock() { for (int i = 0; i < size; i++) { criticals[i]->unlock(); } delete[] criticals; } 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--; } 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--; } 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(); } 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); } } cs.unlock(); } bool Framework::ReadWriteLock::tryLockRead() { cs.lock(); if (writerCount > 0 && writerThread != currentThreadId) { cs.unlock(); return false; } 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; } writerThread = currentThreadId; writerCount++; cs.unlock(); return true; } Lock& Framework::ReadWriteLock::getReadLock() const { return *readLock; } Lock& Framework::ReadWriteLock::getWriteLock() const { return *writeLock; }