trwsync.pp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. { guarantee at least one sleep }
  52. if i=50000 then
  53. sleep(20+random(30))
  54. else if (random(10000)=0) then
  55. sleep(20);
  56. { this must cause data races/loss at some point }
  57. gcount:=l+1;
  58. lock.endread;
  59. r:=random(30000);
  60. if (r=0) then
  61. sleep(30);
  62. end;
  63. end;
  64. procedure twritecounter.execute;
  65. var
  66. i: longint;
  67. l: longint;
  68. r: longint;
  69. begin
  70. for i:=1 to 500 do
  71. begin
  72. lock.beginwrite;
  73. inc(flocalcount);
  74. l:=gcount;
  75. { guarantee at least one sleep }
  76. if i=250 then
  77. sleep(20+random(30))
  78. else if (random(100)=0) then
  79. sleep(20);
  80. { we must be exclusive }
  81. if gcount<>l then
  82. begin
  83. writeln('error 1');
  84. halt(1);
  85. end;
  86. gcount:=l+1;
  87. lock.endwrite;
  88. r:=random(30);
  89. if (r>28) then
  90. sleep(r);
  91. end;
  92. end;
  93. procedure terrorcheck.execute;
  94. begin
  95. { make sure we don't exit before this thread has initialised, since }
  96. { it can allocate memory in its initialisation, which would cause }
  97. { problems for heaptrc as it goes over the memory map in its exit code }
  98. waiting:=true;
  99. { avoid deadlocks/bugs from causing this test to never quit }
  100. sleep(1000*60);
  101. writeln('error 4');
  102. halt(4);
  103. end;
  104. var
  105. r1,r2,r3,r4,r5,r6: treadcounter;
  106. w1,w2,w3,w4: twritecounter;
  107. begin
  108. waiting:=false;
  109. terrorcheck.create(false);
  110. randomize;
  111. lock:=TMultiReadExclusiveWriteSynchronizer.create;
  112. { verify that the lock is recursive }
  113. lock.beginwrite;
  114. lock.beginwrite;
  115. lock.endwrite;
  116. lock.endwrite;
  117. { first try some writers }
  118. w1:=twritecounter.create;
  119. w2:=twritecounter.create;
  120. w3:=twritecounter.create;
  121. w4:=twritecounter.create;
  122. w1.resume;
  123. w2.resume;
  124. w3.resume;
  125. w4.resume;
  126. w1.waitfor;
  127. w2.waitfor;
  128. w3.waitfor;
  129. w4.waitfor;
  130. { must not have caused any data races }
  131. if (gcount<>w1.localcount+w2.localcount+w3.localcount+w4.localcount) then
  132. begin
  133. writeln('error 2');
  134. halt(2);
  135. end;
  136. w1.free;
  137. w2.free;
  138. w3.free;
  139. w4.free;
  140. { now try some mixed readers/writers }
  141. gcount:=0;
  142. r1:=treadcounter.create;
  143. r2:=treadcounter.create;
  144. r3:=treadcounter.create;
  145. r4:=treadcounter.create;
  146. r5:=treadcounter.create;
  147. r6:=treadcounter.create;
  148. w1:=twritecounter.create;
  149. w2:=twritecounter.create;
  150. r1.resume;
  151. r2.resume;
  152. r3.resume;
  153. r4.resume;
  154. r5.resume;
  155. r6.resume;
  156. w1.resume;
  157. w2.resume;
  158. r1.waitfor;
  159. r2.waitfor;
  160. r3.waitfor;
  161. r4.waitfor;
  162. r5.waitfor;
  163. r6.waitfor;
  164. w1.waitfor;
  165. w2.waitfor;
  166. { updating via the readcount must have caused data races }
  167. if (gcount>=r1.localcount+r2.localcount+r3.localcount+r4.localcount+r5.localcount+r6.localcount+w1.localcount+w2.localcount) then
  168. begin
  169. writeln('error 3');
  170. halt(3);
  171. end;
  172. r1.free;
  173. r2.free;
  174. r3.free;
  175. r4.free;
  176. r5.free;
  177. r6.free;
  178. w1.free;
  179. w2.free;
  180. lock.free;
  181. while not waiting do
  182. sleep(20);
  183. end.