Critical.cpp 10 KB

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