public async Task NoRaceBetweenFlushOnAddAndOnDemand() { const int attempts = 100 * 1000; const int batchSize = 5; _queue = new AsyncBatchQueue <int>(batchSize); for (int attemptNumber = 0; attemptNumber < attempts; attemptNumber++) { AddAllItemsButOne(batchSize); using (ManualResetEvent trigger = new ManualResetEvent(initialState: false)) { Task addTask = Task.Run ( () => { trigger.WaitOne(); _queue.Add(666); } ); Task flushTask = Task.Run ( () => { trigger.WaitOne(); _queue.Flush(); } ); trigger.Set(); await addTask.ConfigureAwait(true); await flushTask.ConfigureAwait(true); IReadOnlyList <int> batch = await _queue.TakeAsync().ConfigureAwait(true); List <int> allItems = batch.ToList(); // This happens if Flush occurred before Add, which means there's another item from Add left unflushed. // Gotta flush once more to extract it. if (batch.Count < batchSize) { _queue.Flush(); IReadOnlyList <int> secondBatch = await _queue.TakeAsync().ConfigureAwait(true); allItems.AddRange(secondBatch); } allItems.Count.Should().BeLessOrEqualTo(batchSize, $"Double flush detected at attempt #{attemptNumber}. Items: {String.Join( ", ", allItems )}"); } } }
public async Task MultithreadingInsertsDontCrash() { int insertThreads = 4; int itemsPerThread = 100; _queue = new AsyncBatchQueue <int>(11); List <Task> insertTasks = Enumerable.Range(1, insertThreads) .Select( _ => Task.Run( () => { for (int i = 0; i < itemsPerThread; i++) { _queue.Add(42); } })) .ToList(); await Task.WhenAll(insertTasks).ConfigureAwait(true); _queue.Flush(); int itemsTaken = 0; while (_queue.Count > 0) { itemsTaken += (await _queue.TakeAsync().ConfigureAwait(true)).Count; } itemsTaken.Should().Be(insertThreads * itemsPerThread); }
public async Task ManualFlushWorks() { int[] array = { 0, 1, 42 }; _queue = new AsyncBatchQueue<int>( 50 ); foreach ( var item in array ) _queue.Add( item ); _queue.Flush(); var batch = await _queue.TakeAsync(); CollectionAssert.AreEqual( array, batch.ToList() ); }
public async Task ManualFlushWorks() { int[] array = { 0, 1, 42 }; _queue = new AsyncBatchQueue <int>(50); foreach (var item in array) { _queue.Add(item); } _queue.Flush(); var batch = await _queue.TakeAsync().ConfigureAwait(true); batch.Should().BeEqualTo(array); }
public async Task MultithreadingInsertsDontCrash() { int insertThreads = 4; int itemsPerThread = 100; _queue = new AsyncBatchQueue<int>( 11 ); List<Task> insertTasks = Enumerable.Range( 1, insertThreads ) .Select( _ => Task.Run( () => { for ( int i = 0; i < itemsPerThread; i++ ) _queue.Add( 42 ); } ) ) .ToList(); await Task.WhenAll( insertTasks ); _queue.Flush(); int itemsTaken = 0; while ( _queue.Count > 0 ) itemsTaken += ( await _queue.TakeAsync() ).Count; Assert.AreEqual( insertThreads * itemsPerThread, itemsTaken ); }