trwsync.pp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. {$ifdef fpc}
  2. {$mode objfpc}
  3. {$h+}
  4. {$endif}
  5. uses
  6. {$ifdef unix}
  7. cthreads,
  8. {$endif}
  9. SysUtils, Classes;
  10. var
  11. lock: TMultiReadExclusiveWriteSynchronizer;
  12. gcount: longint;
  13. waiting: boolean;
  14. type
  15. terrorcheck = class(tthread)
  16. procedure execute; override;
  17. end;
  18. tcounter = class(tthread)
  19. private
  20. flock: TMultiReadExclusiveWriteSynchronizer;
  21. flocalcount: longint;
  22. public
  23. constructor create;
  24. property localcount: longint read flocalcount;
  25. end;
  26. treadcounter = class(tcounter)
  27. procedure execute; override;
  28. end;
  29. twritecounter = class(tcounter)
  30. procedure execute; override;
  31. end;
  32. constructor tcounter.create;
  33. begin
  34. { create suspended }
  35. inherited create(true);
  36. freeonterminate:=false;
  37. flock:=lock;
  38. flocalcount:=0;
  39. end;
  40. procedure treadcounter.execute;
  41. var
  42. i: longint;
  43. l: longint;
  44. r: longint;
  45. begin
  46. for i:=1 to 100000 do
  47. begin
  48. lock.beginread;
  49. inc(flocalcount);
  50. l:=gcount;
  51. if (random(10000)=0) then
  52. sleep(20);
  53. { this must cause data races/loss at some point }
  54. gcount:=l+1;
  55. lock.endread;
  56. r:=random(30000);
  57. if (r=0) then
  58. sleep(30);
  59. end;
  60. end;
  61. procedure twritecounter.execute;
  62. var
  63. i: longint;
  64. l: longint;
  65. r: longint;
  66. begin
  67. for i:=1 to 500 do
  68. begin
  69. lock.beginwrite;
  70. inc(flocalcount);
  71. l:=gcount;
  72. if (random(100)=0) then
  73. sleep(20);
  74. { we must be exclusive }
  75. if gcount<>l then
  76. halt(1);
  77. gcount:=l+1;
  78. lock.endwrite;
  79. r:=random(30);
  80. if (r>28) then
  81. sleep(r);
  82. end;
  83. end;
  84. procedure terrorcheck.execute;
  85. begin
  86. { make sure we don't exit before this thread has initialised, since }
  87. { it can allocate memory in its initialisation, which would cause }
  88. { problems for heaptrc as it goes over the memory map in its exit code }
  89. waiting:=true;
  90. { avoid deadlocks/bugs from causing this test to never quit }
  91. sleep(1000*15);
  92. writeln('error 3');
  93. halt(4);
  94. end;
  95. var
  96. r1,r2,r3,r4,r5,r6: treadcounter;
  97. w1,w2,w3,w4: twritecounter;
  98. begin
  99. waiting:=false;
  100. terrorcheck.create(false);
  101. randomize;
  102. lock:=TMultiReadExclusiveWriteSynchronizer.create;
  103. { verify that the lock is recursive }
  104. lock.beginwrite;
  105. lock.beginwrite;
  106. lock.endwrite;
  107. lock.endwrite;
  108. { first try some writers }
  109. w1:=twritecounter.create;
  110. w2:=twritecounter.create;
  111. w3:=twritecounter.create;
  112. w4:=twritecounter.create;
  113. w1.resume;
  114. w2.resume;
  115. w3.resume;
  116. w4.resume;
  117. w1.waitfor;
  118. w2.waitfor;
  119. w3.waitfor;
  120. w4.waitfor;
  121. { must not have caused any data races }
  122. if (gcount<>w1.localcount+w2.localcount+w3.localcount+w4.localcount) then
  123. halt(2);
  124. w1.free;
  125. w2.free;
  126. w3.free;
  127. w4.free;
  128. { now try some mixed readers/writers }
  129. gcount:=0;
  130. r1:=treadcounter.create;
  131. r2:=treadcounter.create;
  132. r3:=treadcounter.create;
  133. r4:=treadcounter.create;
  134. r5:=treadcounter.create;
  135. r6:=treadcounter.create;
  136. w1:=twritecounter.create;
  137. w2:=twritecounter.create;
  138. r1.resume;
  139. r2.resume;
  140. r3.resume;
  141. r4.resume;
  142. r5.resume;
  143. r6.resume;
  144. w1.resume;
  145. w2.resume;
  146. r1.waitfor;
  147. r2.waitfor;
  148. r3.waitfor;
  149. r4.waitfor;
  150. r5.waitfor;
  151. r6.waitfor;
  152. w1.waitfor;
  153. w2.waitfor;
  154. { updating via the readcount must have caused data races }
  155. if (gcount>=r1.localcount+r2.localcount+r3.localcount+r4.localcount+r5.localcount+r6.localcount+w1.localcount+w2.localcount) then
  156. halt(3);
  157. r1.free;
  158. r2.free;
  159. r3.free;
  160. r4.free;
  161. r5.free;
  162. r6.free;
  163. w1.free;
  164. w2.free;
  165. lock.free;
  166. while not waiting do
  167. sleep(20);
  168. end.