Critical.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #include "Critical.h"
  2. #include <iostream>
  3. #include <time.h>
  4. #include "Globals.h"
  5. #include "Thread.h"
  6. using namespace Framework;
  7. // Content of the Critical class from Critical.h
  8. // Konstructor
  9. Critical::Critical()
  10. {
  11. InitializeCriticalSection(&cs);
  12. lockCount = 0;
  13. }
  14. // Destructor
  15. Critical::~Critical()
  16. {
  17. DeleteCriticalSection(&cs);
  18. }
  19. // locks the object
  20. void Critical::lock()
  21. {
  22. currentThreadLockCount++;
  23. EnterCriticalSection(&cs);
  24. lockCount++;
  25. }
  26. // tries to lock the object
  27. bool Critical::tryLock()
  28. {
  29. if (lockCount > 0) return false;
  30. currentThreadLockCount++;
  31. EnterCriticalSection(&cs);
  32. lockCount++;
  33. return true;
  34. }
  35. // unlocks the object
  36. void Critical::unlock()
  37. {
  38. if (lockCount <= 0)
  39. {
  40. throw "A Thread tried to unlock a critical that was not locked before";
  41. }
  42. lockCount--;
  43. LeaveCriticalSection(&cs);
  44. currentThreadLockCount--;
  45. }
  46. // returns true if the object is locked
  47. bool Critical::isLocked() const
  48. {
  49. return lockCount > 0;
  50. }
  51. Synchronizer::Synchronizer()
  52. : numWaiting(0),
  53. skip(0)
  54. {}
  55. Synchronizer::~Synchronizer()
  56. {
  57. skip = 1;
  58. std::unique_lock<std::mutex> lk(mutex);
  59. if (numWaiting > 0)
  60. {
  61. lk.unlock();
  62. block.notify_all();
  63. }
  64. else
  65. lk.unlock();
  66. while (numWaiting > 0)
  67. Sleep(10);
  68. lk.lock();
  69. }
  70. bool Synchronizer::wait()
  71. {
  72. std::unique_lock<std::mutex> lk(mutex);
  73. if (skip) return false;
  74. numWaiting++;
  75. block.wait(lk);
  76. numWaiting--;
  77. return !skip;
  78. }
  79. bool Synchronizer::wait(int milisec)
  80. {
  81. std::unique_lock<std::mutex> lk(mutex);
  82. if (skip) return false;
  83. numWaiting++;
  84. std::cv_status status
  85. = block.wait_for(lk, std::chrono::milliseconds(milisec));
  86. numWaiting--;
  87. return !skip && status == std::cv_status::no_timeout;
  88. }
  89. void Synchronizer::notify()
  90. {
  91. block.notify_one();
  92. }
  93. void Synchronizer::notify(int amount)
  94. {
  95. while (amount--)
  96. block.notify_one();
  97. }
  98. void Synchronizer::notifyAll()
  99. {
  100. block.notify_all();
  101. }
  102. int Synchronizer::getNumberOfWaitingThreads() const
  103. {
  104. return numWaiting;
  105. }
  106. Framework::StackLock::StackLock(std::initializer_list<Lock*> locks)
  107. {
  108. this->locks = new Lock*[locks.size()];
  109. int i = 0;
  110. for (Lock* c : locks)
  111. {
  112. this->locks[i] = c;
  113. i++;
  114. }
  115. size = (int)locks.size();
  116. if (size > 0)
  117. {
  118. this->locks[0]->lock();
  119. int index = 1;
  120. while (index < size)
  121. {
  122. if (!this->locks[index]->tryLock())
  123. {
  124. for (int i = 0; i < index; i++)
  125. {
  126. this->locks[i]->unlock();
  127. }
  128. this->locks[index]->lock();
  129. this->locks[index]->unlock();
  130. this->locks[0]->lock();
  131. index = 1;
  132. }
  133. else
  134. index++;
  135. }
  136. }
  137. }
  138. Framework::StackLock::~StackLock()
  139. {
  140. for (int i = 0; i < size; i++)
  141. {
  142. locks[i]->unlock();
  143. }
  144. delete[] locks;
  145. }
  146. class Framework::InternalReadLock : public Lock
  147. {
  148. private:
  149. ReadWriteLock* rwLock;
  150. public:
  151. InternalReadLock(ReadWriteLock* rwLock)
  152. : rwLock(rwLock)
  153. {}
  154. virtual ~InternalReadLock() = default;
  155. void lock() override
  156. {
  157. rwLock->lockRead();
  158. }
  159. void unlock() override
  160. {
  161. rwLock->unlockRead();
  162. }
  163. bool tryLock() override
  164. {
  165. return rwLock->tryLockRead();
  166. }
  167. };
  168. class Framework::InternalWriteLock : public Lock
  169. {
  170. private:
  171. ReadWriteLock* rwLock;
  172. public:
  173. InternalWriteLock(ReadWriteLock* rwLock)
  174. : rwLock(rwLock)
  175. {}
  176. virtual ~InternalWriteLock() = default;
  177. void lock() override
  178. {
  179. rwLock->lockWrite();
  180. }
  181. void unlock() override
  182. {
  183. rwLock->unlockWrite();
  184. }
  185. bool tryLock() override
  186. {
  187. return rwLock->tryLockWrite();
  188. }
  189. };
  190. Framework::ReadWriteLock::ReadWriteLock(int initialMaxSize)
  191. : readerThreads(new int[initialMaxSize]),
  192. readCounters(new int[initialMaxSize]),
  193. maxSize(initialMaxSize),
  194. readerThreadCount(0),
  195. writerThread(0),
  196. writerCount(0),
  197. waitingReaders(0),
  198. waitingWriters(0),
  199. readLock(new InternalReadLock(this)),
  200. writeLock(new InternalWriteLock(this))
  201. {
  202. memset(readerThreads, 0, sizeof(int) * initialMaxSize);
  203. memset(readCounters, 0, sizeof(int) * initialMaxSize);
  204. }
  205. Framework::ReadWriteLock::~ReadWriteLock()
  206. {
  207. delete[] readerThreads;
  208. delete[] readCounters;
  209. delete readLock;
  210. delete writeLock;
  211. }
  212. void Framework::ReadWriteLock::lockRead()
  213. {
  214. cs.lock();
  215. while (writerCount > 0 && writerThread != currentThreadId)
  216. {
  217. waitingReaders++;
  218. cs.unlock();
  219. readerBlock.wait();
  220. cs.lock();
  221. waitingReaders--;
  222. }
  223. currentThreadLockCount++;
  224. int index = -1;
  225. for (int i = 0; i < readerThreadCount; i++)
  226. {
  227. if (readerThreads[i] == currentThreadId)
  228. {
  229. index = i;
  230. break;
  231. }
  232. }
  233. if (index == -1)
  234. {
  235. if (readerThreadCount == maxSize)
  236. {
  237. int* newReaderThreads = new int[maxSize * 2];
  238. int* newReadCounters = new int[maxSize * 2];
  239. for (int i = 0; i < maxSize; i++)
  240. {
  241. newReaderThreads[i] = readerThreads[i];
  242. newReadCounters[i] = readCounters[i];
  243. }
  244. delete[] readerThreads;
  245. delete[] readCounters;
  246. readerThreads = newReaderThreads;
  247. readCounters = newReadCounters;
  248. maxSize *= 2;
  249. }
  250. index = readerThreadCount++;
  251. readerThreads[index] = currentThreadId;
  252. readCounters[index] = 0;
  253. }
  254. readCounters[index]++;
  255. cs.unlock();
  256. }
  257. void Framework::ReadWriteLock::lockWrite()
  258. {
  259. cs.lock();
  260. while (
  261. (writerCount > 0 && writerThread != currentThreadId)
  262. || (readerThreadCount > 0
  263. && (readerThreadCount != 1 || readerThreads[0] != currentThreadId)))
  264. {
  265. waitingWriters++;
  266. cs.unlock();
  267. writerBlock.wait();
  268. cs.lock();
  269. waitingWriters--;
  270. }
  271. currentThreadLockCount++;
  272. writerThread = currentThreadId;
  273. writerCount++;
  274. cs.unlock();
  275. }
  276. void Framework::ReadWriteLock::unlockRead()
  277. {
  278. cs.lock();
  279. int index = -1;
  280. for (int i = 0; i < readerThreadCount; i++)
  281. {
  282. if (readerThreads[i] == currentThreadId)
  283. {
  284. index = i;
  285. break;
  286. }
  287. }
  288. if (index == -1 || readCounters[index] == 0)
  289. {
  290. cs.unlock();
  291. throw "A Thread that does not hold a read lock tries to unlock it";
  292. }
  293. readCounters[index]--;
  294. if (readCounters[index] == 0)
  295. {
  296. readerThreads[index] = readerThreads[readerThreadCount - 1];
  297. readCounters[index] = readCounters[readerThreadCount - 1];
  298. readerThreadCount--;
  299. }
  300. if (readerThreadCount == 0 && waitingWriters > 0)
  301. {
  302. writerBlock.notify();
  303. }
  304. currentThreadLockCount--;
  305. cs.unlock();
  306. }
  307. void Framework::ReadWriteLock::unlockWrite()
  308. {
  309. cs.lock();
  310. if (writerThread != currentThreadId || writerCount == 0)
  311. {
  312. cs.unlock();
  313. throw "A Thread that does not hold the write lock tries to unlock it";
  314. }
  315. writerCount--;
  316. if (writerCount == 0)
  317. {
  318. if (waitingWriters > 0)
  319. {
  320. writerBlock.notify();
  321. }
  322. else if (waitingReaders > 0)
  323. {
  324. readerBlock.notify(waitingReaders);
  325. }
  326. }
  327. currentThreadLockCount--;
  328. cs.unlock();
  329. }
  330. bool Framework::ReadWriteLock::tryLockRead()
  331. {
  332. cs.lock();
  333. if (writerCount > 0 && writerThread != currentThreadId)
  334. {
  335. cs.unlock();
  336. return false;
  337. }
  338. currentThreadLockCount++;
  339. int index = -1;
  340. for (int i = 0; i < readerThreadCount; i++)
  341. {
  342. if (readerThreads[i] == currentThreadId)
  343. {
  344. index = i;
  345. break;
  346. }
  347. }
  348. if (index == -1)
  349. {
  350. if (readerThreadCount == maxSize)
  351. {
  352. int* newReaderThreads = new int[maxSize * 2];
  353. int* newReadCounters = new int[maxSize * 2];
  354. for (int i = 0; i < maxSize; i++)
  355. {
  356. newReaderThreads[i] = readerThreads[i];
  357. newReadCounters[i] = readCounters[i];
  358. }
  359. delete[] readerThreads;
  360. delete[] readCounters;
  361. readerThreads = newReaderThreads;
  362. readCounters = newReadCounters;
  363. maxSize *= 2;
  364. }
  365. index = readerThreadCount++;
  366. readerThreads[index] = currentThreadId;
  367. readCounters[index] = 0;
  368. }
  369. readCounters[index]++;
  370. cs.unlock();
  371. return true;
  372. }
  373. bool Framework::ReadWriteLock::tryLockWrite()
  374. {
  375. cs.lock();
  376. if ((writerCount > 0 && writerThread != currentThreadId)
  377. || (readerThreadCount > 0
  378. && (readerThreadCount != 1 || readerThreads[0] != currentThreadId)))
  379. {
  380. cs.unlock();
  381. return false;
  382. }
  383. currentThreadLockCount++;
  384. writerThread = currentThreadId;
  385. writerCount++;
  386. cs.unlock();
  387. return true;
  388. }
  389. Lock& Framework::ReadWriteLock::getReadLock() const
  390. {
  391. return *readLock;
  392. }
  393. Lock& Framework::ReadWriteLock::getWriteLock() const
  394. {
  395. return *writeLock;
  396. }
  397. int Framework::ReadWriteLock::getReadThreadCount() const
  398. {
  399. return readerThreadCount;
  400. }
  401. bool Framework::ReadWriteLock::isWriteLocked() const
  402. {
  403. return writerCount > 0;
  404. }
  405. int Framework::ReadWriteLock::getReadThread(int index) const
  406. {
  407. if (index < 0 || index >= readerThreadCount)
  408. {
  409. throw "Index out of bounds";
  410. }
  411. return readerThreads[index];
  412. }
  413. int Framework::ReadWriteLock::getWriteLockThread() const
  414. {
  415. return writerThread;
  416. }
  417. int Framework::ReadWriteLock::getWriteLockCount() const
  418. {
  419. return writerCount;
  420. }
  421. int Framework::ReadWriteLock::getReadLockCount(int threadId) const
  422. {
  423. for (int i = 0; i < readerThreadCount; i++)
  424. {
  425. if (readerThreads[i] == threadId)
  426. {
  427. return readCounters[i];
  428. }
  429. }
  430. return 0;
  431. }