Skip to content

Commit bbf2a71

Browse files
Add the ordering demonstration: own-queue LIFO drain and a steal from a dedicated thread
DrainOwnQueue fills a bag and drains it on the same thread, which returns the items last in, first out. DrainStolenQueue fills the bag on one dedicated thread and drains it on another, so the consumer steals from the head of the producer's queue and the items come back oldest first. Both use dedicated Thread objects with Join(), never Task.Run: the pool is free to hand the producer and the consumer to the same thread, which makes the consumer pop its own queue LIFO instead of stealing and the assertion intermittently red. Two tests added. The suite runs 10 of 10 on five consecutive runs.
1 parent d81e19d commit bbf2a71

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

‎collections-csharp/ConcurrentBagInCSharp/ConcurrentBagInCSharp/ConcurrentBagDemo.cs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,54 @@ public static void AccessItemFromAConcurrentBagConcurrently(ConcurrentBag<int> b
8282
});
8383
}
8484

85+
public static List<int> DrainOwnQueue()
86+
{
87+
var bag = new ConcurrentBag<int>();
88+
for (var i = 1; i <= 5; i++)
89+
{
90+
bag.Add(i);
91+
}
92+
93+
var taken = new List<int>();
94+
while (bag.TryTake(out var item))
95+
{
96+
taken.Add(item);
97+
}
98+
99+
return taken;
100+
}
101+
102+
public static List<int> DrainStolenQueue()
103+
{
104+
var bag = new ConcurrentBag<int>();
105+
var taken = new List<int>();
106+
107+
// Dedicated threads, never Task.Run: the thread pool is free to hand both pieces of
108+
// work to the same thread, and a consumer running on the producer's thread pops its
109+
// own queue last in, first out instead of stealing.
110+
var producer = new Thread(() =>
111+
{
112+
for (var i = 0; i < 5; i++)
113+
{
114+
bag.Add(i);
115+
}
116+
});
117+
producer.Start();
118+
producer.Join();
119+
120+
var consumer = new Thread(() =>
121+
{
122+
while (bag.TryTake(out var item))
123+
{
124+
taken.Add(item);
125+
}
126+
});
127+
consumer.Start();
128+
consumer.Join();
129+
130+
return taken;
131+
}
132+
85133
public static int[] ConcurrentBagToArrayMethod(ConcurrentBag<int> bag)
86134
{
87135
return bag.ToArray();

‎collections-csharp/ConcurrentBagInCSharp/Tests/ConcurrentBagInCSharpTest.cs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ public void GivenAConcurrentBag_WhenConvertingToAnArray_ThenReturnsAnArray()
6363
Assert.NotEmpty(result);
6464
}
6565

66+
[Fact]
67+
public void GivenAConcurrentBagFilledOnOneThread_WhenDrainingOnThatThread_ThenReturnsItemsLastInFirstOut()
68+
{
69+
var result = ConcurrentBagDemo.DrainOwnQueue();
70+
71+
Assert.Equal(new List<int> { 5, 4, 3, 2, 1 }, result);
72+
}
73+
74+
[Fact]
75+
public void GivenAConcurrentBagFilledOnOneThread_WhenDrainingOnADifferentThread_ThenReturnsItemsOldestFirst()
76+
{
77+
var result = ConcurrentBagDemo.DrainStolenQueue();
78+
79+
Assert.Equal(new List<int> { 0, 1, 2, 3, 4 }, result);
80+
}
81+
6682
[Fact]
6783
public void GivenAConcurrentBag_WhenClearingAConcurrentBag_ThenReturnsAnEmptyConcurrentBag()
6884
{

0 commit comments

Comments
 (0)