11
2+ using System ;
23using System . Threading ;
34using System . Threading . Tasks ;
45using BitFaster . Caching . Atomic ;
@@ -118,7 +119,9 @@ public void WhenArgObjectValuesAreSameEqualsTrue()
118119 [ Fact ]
119120 public async Task WhenCallersRunConcurrentlyResultIsFromWinner ( )
120121 {
121- var enter = new ManualResetEvent ( false ) ;
122+ var enter1 = new ManualResetEvent ( false ) ;
123+ var enter2 = new ManualResetEvent ( false ) ;
124+ var factory = new ManualResetEvent ( false ) ;
122125 var resume = new ManualResetEvent ( false ) ;
123126
124127 var atomicFactory = new AtomicFactory < int , int > ( ) ;
@@ -127,9 +130,10 @@ public async Task WhenCallersRunConcurrentlyResultIsFromWinner()
127130
128131 Task < int > first = Task . Run ( ( ) =>
129132 {
133+ enter1 . Set ( ) ;
130134 return atomicFactory . GetValue ( 1 , k =>
131135 {
132- enter . Set ( ) ;
136+ factory . Set ( ) ;
133137 resume . WaitOne ( ) ;
134138
135139 result = 1 ;
@@ -140,9 +144,10 @@ public async Task WhenCallersRunConcurrentlyResultIsFromWinner()
140144
141145 Task < int > second = Task . Run ( ( ) =>
142146 {
147+ enter2 . Set ( ) ;
143148 return atomicFactory . GetValue ( 1 , k =>
144149 {
145- enter . Set ( ) ;
150+ factory . Set ( ) ;
146151 resume . WaitOne ( ) ;
147152
148153 result = 2 ;
@@ -151,13 +156,114 @@ public async Task WhenCallersRunConcurrentlyResultIsFromWinner()
151156 } ) ;
152157 } ) ;
153158
154- enter . WaitOne ( ) ;
159+ enter1 . WaitOne ( ) ;
160+ enter2 . WaitOne ( ) ;
161+ factory . WaitOne ( ) ;
155162 resume . Set ( ) ;
156163
157164 ( await first ) . Should ( ) . Be ( result ) ;
158165 ( await second ) . Should ( ) . Be ( result ) ;
159166
160167 winnerCount . Should ( ) . Be ( 1 ) ;
161168 }
169+
170+ [ Fact ]
171+ public async Task WhenCallersRunConcurrentlyAndFailExceptionIsPropogated ( )
172+ {
173+ var enter1 = new ManualResetEvent ( false ) ;
174+ var enter2 = new ManualResetEvent ( false ) ;
175+ var factory = new ManualResetEvent ( false ) ;
176+ var resume = new ManualResetEvent ( false ) ;
177+
178+ var atomicFactory = new AtomicFactory < int , int > ( ) ;
179+ var throwCount = 0 ;
180+
181+ Task < int > first = Task . Run ( ( ) =>
182+ {
183+ enter1 . Set ( ) ;
184+ return atomicFactory . GetValue ( 1 , k =>
185+ {
186+ factory . Set ( ) ;
187+ resume . WaitOne ( ) ;
188+
189+ Interlocked . Increment ( ref throwCount ) ;
190+ throw new Exception ( ) ;
191+ } ) ;
192+ } ) ;
193+
194+ Task < int > second = Task . Run ( ( ) =>
195+ {
196+ enter2 . Set ( ) ;
197+ return atomicFactory . GetValue ( 1 , k =>
198+ {
199+ factory . Set ( ) ;
200+ resume . WaitOne ( ) ;
201+
202+ Interlocked . Increment ( ref throwCount ) ;
203+ throw new Exception ( ) ;
204+ } ) ;
205+ } ) ;
206+
207+ enter1 . WaitOne ( ) ;
208+ enter2 . WaitOne ( ) ;
209+ factory . WaitOne ( ) ;
210+ resume . Set ( ) ;
211+
212+ Func < Task > act1 = ( ) => first ;
213+ Func < Task > act2 = ( ) => second ;
214+
215+ await act1 . Should ( ) . ThrowAsync < Exception > ( ) ;
216+ await act2 . Should ( ) . ThrowAsync < Exception > ( ) ;
217+
218+ // verify only one exception was thrown
219+ throwCount . Should ( ) . Be ( 1 ) ;
220+ }
221+
222+ [ Fact ]
223+ public async Task WhenCallersRunConcurrentlyAndFailNewCallerStartsClean ( )
224+ {
225+ var enter1 = new ManualResetEvent ( false ) ;
226+ var enter2 = new ManualResetEvent ( false ) ;
227+ var factory = new ManualResetEvent ( false ) ;
228+ var resume = new ManualResetEvent ( false ) ;
229+
230+ var atomicFactory = new AtomicFactory < int , int > ( ) ;
231+
232+ Task < int > first = Task . Run ( ( ) =>
233+ {
234+ enter1 . Set ( ) ;
235+ return atomicFactory . GetValue ( 1 , k =>
236+ {
237+ factory . Set ( ) ;
238+ resume . WaitOne ( ) ;
239+ throw new Exception ( ) ;
240+ } ) ;
241+ } ) ;
242+
243+ Task < int > second = Task . Run ( ( ) =>
244+ {
245+ enter2 . Set ( ) ;
246+ return atomicFactory . GetValue ( 1 , k =>
247+ {
248+ factory . Set ( ) ;
249+ resume . WaitOne ( ) ;
250+ throw new Exception ( ) ;
251+ } ) ;
252+ } ) ;
253+
254+ enter1 . WaitOne ( ) ;
255+ enter2 . WaitOne ( ) ;
256+ factory . WaitOne ( ) ;
257+ resume . Set ( ) ;
258+
259+ Func < Task > act1 = ( ) => first ;
260+ Func < Task > act2 = ( ) => second ;
261+
262+ await act1 . Should ( ) . ThrowAsync < Exception > ( ) ;
263+ await act2 . Should ( ) . ThrowAsync < Exception > ( ) ;
264+
265+ // verify exception is no longer cached
266+ atomicFactory . GetValue ( 1 , k => k ) . Should ( ) . Be ( 1 ) ;
267+ }
162268 }
163269}
0 commit comments