@@ -135,6 +135,170 @@ await Parallel.ForAsync(0, COUNT, (index, _) =>
135135 } ) ;
136136 }
137137
138+ [ Fact ]
139+ public void GetOrAdd ( )
140+ {
141+ const int COUNT = 1_0000 ;
142+
143+ var keys = System . Linq . Enumerable . Range ( 0 , COUNT ) . ToArray ( ) ;
144+ Random . Shared . Shuffle ( keys ) ;
145+
146+ var dictionary = new SynchronizedDictionary < int , string > ( COUNT ) ;
147+ for ( int i = 0 ; i < COUNT ; i ++ )
148+ {
149+ if ( i % 2 == 1 )
150+ dictionary [ i ] = $ "Value#{ i } ";
151+ }
152+
153+ Assert . Equal ( COUNT / 2 , dictionary . Count ) ;
154+
155+ Parallel . For ( 0 , COUNT , index =>
156+ {
157+ var key = keys [ index ] ;
158+ var value = dictionary . GetOrAdd ( key , key => $ "Added#{ key } ") ;
159+
160+ if ( key % 2 == 0 )
161+ Assert . Equal ( $ "Added#{ key } ", value ) ;
162+ else
163+ Assert . Equal ( $ "Value#{ key } ", value ) ;
164+
165+ if ( index % 100 == 0 )
166+ {
167+ foreach ( var item in dictionary )
168+ {
169+ Assert . True ( item . Key >= 0 ) ;
170+ Assert . True ( dictionary . ContainsKey ( item . Key ) ) ;
171+ }
172+ }
173+ } ) ;
174+
175+ Assert . Equal ( COUNT , dictionary . Count ) ;
176+ }
177+
178+ [ Fact ]
179+ public async Task GetOrAddAsync ( )
180+ {
181+ const int COUNT = 1_0000 ;
182+
183+ var keys = System . Linq . Enumerable . Range ( 0 , COUNT ) . ToArray ( ) ;
184+ Random . Shared . Shuffle ( keys ) ;
185+
186+ var dictionary = new SynchronizedDictionary < int , string > ( COUNT ) ;
187+ for ( int i = 0 ; i < COUNT ; i ++ )
188+ {
189+ if ( i % 2 == 1 )
190+ dictionary [ i ] = $ "Value#{ i } ";
191+ }
192+
193+ Assert . Equal ( COUNT / 2 , dictionary . Count ) ;
194+
195+ await Parallel . ForAsync ( 0 , COUNT , ( index , _ ) =>
196+ {
197+ var key = keys [ index ] ;
198+ var value = dictionary . GetOrAdd ( key , key => $ "Added#{ key } ") ;
199+
200+ if ( key % 2 == 0 )
201+ Assert . Equal ( $ "Added#{ key } ", value ) ;
202+ else
203+ Assert . Equal ( $ "Value#{ key } ", value ) ;
204+
205+ if ( index % 100 == 0 )
206+ {
207+ foreach ( var item in dictionary )
208+ {
209+ Assert . True ( item . Key >= 0 ) ;
210+ Assert . True ( dictionary . ContainsKey ( item . Key ) ) ;
211+ }
212+ }
213+
214+ return ValueTask . CompletedTask ;
215+ } ) ;
216+
217+ Assert . Equal ( COUNT , dictionary . Count ) ;
218+ }
219+
220+ [ Fact ]
221+ public void AddOrUpdate ( )
222+ {
223+ const int COUNT = 1_0000 ;
224+
225+ var keys = System . Linq . Enumerable . Range ( 0 , COUNT ) . ToArray ( ) ;
226+ Random . Shared . Shuffle ( keys ) ;
227+
228+ var dictionary = new SynchronizedDictionary < int , string > ( COUNT ) ;
229+ for ( int i = 0 ; i < COUNT ; i ++ )
230+ {
231+ if ( i % 2 == 1 )
232+ dictionary [ i ] = $ "Value#{ i } ";
233+ }
234+
235+ Assert . Equal ( COUNT / 2 , dictionary . Count ) ;
236+
237+ Parallel . For ( 0 , COUNT , index =>
238+ {
239+ var key = keys [ index ] ;
240+ var value = dictionary . AddOrUpdate ( key , key => $ "Added#{ key } ", ( key , value ) => $ "Updated#{ key } ") ;
241+
242+ if ( key % 2 == 0 )
243+ Assert . Equal ( $ "Added#{ key } ", value ) ;
244+ else
245+ Assert . Equal ( $ "Updated#{ key } ", value ) ;
246+
247+ if ( index % 100 == 0 )
248+ {
249+ foreach ( var item in dictionary )
250+ {
251+ Assert . True ( item . Key >= 0 ) ;
252+ Assert . True ( dictionary . ContainsKey ( item . Key ) ) ;
253+ }
254+ }
255+ } ) ;
256+
257+ Assert . Equal ( COUNT , dictionary . Count ) ;
258+ }
259+
260+ [ Fact ]
261+ public async Task AddOrUpdateAsync ( )
262+ {
263+ const int COUNT = 1_0000 ;
264+
265+ var keys = System . Linq . Enumerable . Range ( 0 , COUNT ) . ToArray ( ) ;
266+ Random . Shared . Shuffle ( keys ) ;
267+
268+ var dictionary = new SynchronizedDictionary < int , string > ( COUNT ) ;
269+ for ( int i = 0 ; i < COUNT ; i ++ )
270+ {
271+ if ( i % 2 == 1 )
272+ dictionary [ i ] = $ "Value#{ i } ";
273+ }
274+
275+ Assert . Equal ( COUNT / 2 , dictionary . Count ) ;
276+
277+ await Parallel . ForAsync ( 0 , COUNT , ( index , _ ) =>
278+ {
279+ var key = keys [ index ] ;
280+ var value = dictionary . AddOrUpdate ( key , key => $ "Added#{ key } ", ( key , value ) => $ "Updated#{ key } ") ;
281+
282+ if ( key % 2 == 0 )
283+ Assert . Equal ( $ "Added#{ key } ", value ) ;
284+ else
285+ Assert . Equal ( $ "Updated#{ key } ", value ) ;
286+
287+ if ( index % 100 == 0 )
288+ {
289+ foreach ( var item in dictionary )
290+ {
291+ Assert . True ( item . Key >= 0 ) ;
292+ Assert . True ( dictionary . ContainsKey ( item . Key ) ) ;
293+ }
294+ }
295+
296+ return ValueTask . CompletedTask ;
297+ } ) ;
298+
299+ Assert . Equal ( COUNT , dictionary . Count ) ;
300+ }
301+
138302 [ Fact ]
139303 public void Remove ( )
140304 {
@@ -200,4 +364,60 @@ await Parallel.ForAsync(0, COUNT, (index, _) =>
200364
201365 Assert . Empty ( dictionary ) ;
202366 }
367+
368+ [ Fact ]
369+ public async Task ChaosAsync ( )
370+ {
371+ const int COUNT = 1_0000 ;
372+
373+ var dictionary = new SynchronizedDictionary < int , string > ( COUNT ) ;
374+ var tasks = new Task [ ]
375+ {
376+ Task . Factory . StartNew ( Run , dictionary ) ,
377+ Task . Factory . StartNew ( Run , dictionary ) ,
378+ Task . Factory . StartNew ( Run , dictionary ) ,
379+ Task . Factory . StartNew ( Run , dictionary ) ,
380+ Task . Factory . StartNew ( Run , dictionary ) ,
381+ } ;
382+
383+ await Task . WhenAll ( tasks ) ;
384+ Assert . Equal ( COUNT , dictionary . Count ) ;
385+
386+ static void Run ( object state )
387+ {
388+ var index = 0 ;
389+ var stopwatch = System . Diagnostics . Stopwatch . StartNew ( ) ;
390+ var dictionary = ( SynchronizedDictionary < int , string > ) state ;
391+
392+ while ( Hit ( dictionary , index , stopwatch . Elapsed ) < COUNT )
393+ index = index >= COUNT ? 0 : index + 1 ;
394+
395+ stopwatch . Stop ( ) ;
396+ }
397+
398+ static int Hit ( SynchronizedDictionary < int , string > dictionary , int key , TimeSpan duration )
399+ {
400+ switch ( Random . Shared . Next ( ) % 10 )
401+ {
402+ case 0 :
403+ if ( duration . TotalSeconds < 1.0 )
404+ dictionary . Remove ( key ) ;
405+ break ;
406+ case 1 :
407+ case 2 :
408+ dictionary . TryAdd ( key , $ "Value#{ key } ") ;
409+ break ;
410+ case 3 :
411+ case 4 :
412+ if ( ! dictionary . TryUpdate ( key , $ "Value.{ key } ") )
413+ dictionary . TryAdd ( key , $ "Value#{ key } ") ;
414+ break ;
415+ default :
416+ dictionary . AddOrUpdate ( key , key => $ "Added:{ key } ", ( key , value ) => $ "Updated:{ key } ") ;
417+ break ;
418+ }
419+
420+ return dictionary . Count ;
421+ }
422+ }
203423}
0 commit comments