Critical.cpp 11 KB

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