Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
using System.Collections.Concurrent;
using System.Collections;

namespace ConcurrentBagInCSharp
{
public class ConcurrentBagDemo
{
public static ConcurrentBag<int> CreateConcurrentBag()
public static ConcurrentBag<int> CreateEmptyConcurrentBag()
{
ConcurrentBag<int> myNumbers = new();
return new ConcurrentBag<int>();
}

var myConcurrentBag = new ConcurrentBag<int>() { 2, 4, 6, 8, 10 };
var myConcurrentBagCount = myConcurrentBag.Count;
public static ConcurrentBag<int> CreateConcurrentBagWithInitialItems()
{
return new ConcurrentBag<int>() { 2, 4, 6, 8, 10 };
}

public static ConcurrentBag<int> CreateConcurrentBag()
{
var myList = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };
var anotherConcurrentBag = new ConcurrentBag<int>(myList);

return anotherConcurrentBag;
return new ConcurrentBag<int>(myList);
}

public static ConcurrentBag<int> CreateAndAddToConcurrentBagConcurrently()
Expand All @@ -30,9 +33,9 @@ public static ConcurrentBag<int> CreateAndAddToConcurrentBagConcurrently()
return numbersBag;
}

public static ArrayList RemoveFromConcurrentBag(ConcurrentBag<int> numbersBag)
public static List<int> RemoveFromConcurrentBag(ConcurrentBag<int> numbersBag)
{
var result = new ArrayList();
var result = new List<int>();
if (numbersBag.TryTake(out int number))
{
result.Add(number);
Expand All @@ -41,9 +44,9 @@ public static ArrayList RemoveFromConcurrentBag(ConcurrentBag<int> numbersBag)
return result;
}

public static ArrayList RemoveFromConcurrentBagConcurrently(ConcurrentBag<int> bag)
public static List<int> RemoveFromConcurrentBagConcurrently(ConcurrentBag<int> bag)
{
var numbersList = new ArrayList();
var numbersList = new List<int>();
Parallel.For(0, 20, i =>
{
if (bag.TryTake(out int number))
Expand All @@ -56,9 +59,9 @@ public static ArrayList RemoveFromConcurrentBagConcurrently(ConcurrentBag<int> b
return numbersList;
}

public static ArrayList AccessItemFromAConcurrentBag(ConcurrentBag<int> bag)
public static List<int> AccessItemFromAConcurrentBag(ConcurrentBag<int> bag)
{
var result = new ArrayList();
var result = new List<int>();

if (bag.TryPeek(out int number))
{
Expand All @@ -79,27 +82,76 @@ public static void AccessItemFromAConcurrentBagConcurrently(ConcurrentBag<int> b
});
}

public static int[] ConcurrentBagToArrayMethod(ConcurrentBag<int> bag)
public static List<int> DrainOwnQueue()
{
var myArray = new int[bag.Count];
myArray = bag.ToArray();
var bag = new ConcurrentBag<int>();
for (var i = 1; i <= 5; i++)
{
bag.Add(i);
}

var taken = new List<int>();
while (bag.TryTake(out var item))
{
taken.Add(item);
}

return myArray;
return taken;
}

public static List<int> DrainStolenQueue()
{
var bag = new ConcurrentBag<int>();
var taken = new List<int>();

// Dedicated threads, never Task.Run: the thread pool is free to hand both pieces of
// work to the same thread, and a consumer running on the producer's thread pops its
// own queue last in, first out instead of stealing.
var producer = new Thread(() =>
{
for (var i = 0; i < 5; i++)
{
bag.Add(i);
}
});
producer.Start();
producer.Join();

var consumer = new Thread(() =>
{
while (bag.TryTake(out var item))
{
taken.Add(item);
}
});
consumer.Start();
consumer.Join();

return taken;
}

public static int[] ConcurrentBagToArrayMethod(ConcurrentBag<int> bag)
{
return bag.ToArray();
}

public static int[] ConcurrentBagCopyToMethod(ConcurrentBag<int> bag)
{
// Count and CopyTo are two separate operations. In a multithreaded program another
// thread can add an item between them, and CopyTo then throws ArgumentException
// because the destination is too short. Size the destination from a snapshot,
// or generously, whenever other threads can still write to the bag.
var someArray = new int[bag.Count];
bag.CopyTo(someArray, 0);

return someArray;
}

public static void ConcurrentBagClearMethod(ConcurrentBag<int> bag)
{
bag.Clear();

Console.WriteLine($"My concurrent bag contains {bag.Count} item."); // My concurrent bag contains 0 item.
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
namespace ConcurrentBagInCSharp
{
internal class Program
{
static void Main(string[] args)
{
var myConcurrentBag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();
var myConcurrentBagCount = myConcurrentBag.Count;
var isMyConcurrentBagEmpty = myConcurrentBag.IsEmpty;

}
}
}
using ConcurrentBagInCSharp;

var myConcurrentBag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();

Console.WriteLine($"Count: {myConcurrentBag.Count}");
Console.WriteLine($"IsEmpty: {myConcurrentBag.IsEmpty}");
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ConcurrentBagInCSharp;
using System.Collections;
using System.Collections.Concurrent;

namespace Tests
Expand All @@ -25,32 +24,32 @@ public void GivenAnEmptyConcurrentBag_WhenAddingToAConcurrentBag_ThenReturnsAPop
}

[Fact]
public void GivenAConcurrentBag_WhenRemovingFromAConcurrentBag_ThenReturnsAnArrayList()
public void GivenAConcurrentBag_WhenRemovingFromAConcurrentBag_ThenReturnsAList()
{
var bag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();
var result = ConcurrentBagDemo.RemoveFromConcurrentBag(bag);

Assert.IsType<ArrayList>(result);
Assert.IsType<List<int>>(result);
Assert.Single(result);
}

[Fact]
public void GivenAConcurrentBag_WhenRemovingFromAConcurrentBagConcurrently_ThenReturnsAnArrayList()
public void GivenAConcurrentBag_WhenRemovingFromAConcurrentBagConcurrently_ThenReturnsAList()
{
var bag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();
var result = ConcurrentBagDemo.RemoveFromConcurrentBagConcurrently(bag);

Assert.IsType<ArrayList>(result);
Assert.IsType<List<int>>(result);
Assert.NotEmpty(result);
}

[Fact]
public void GivenAConcurrentBag_WhenReadingFromAConcurrentBag_ThenReturnsAnArrayList()
public void GivenAConcurrentBag_WhenReadingFromAConcurrentBag_ThenReturnsAList()
{
var bag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();
var result = ConcurrentBagDemo.AccessItemFromAConcurrentBag(bag);

Assert.IsType<ArrayList>(result);
Assert.IsType<List<int>>(result);
Assert.Single(result);
}

Expand All @@ -64,6 +63,33 @@ public void GivenAConcurrentBag_WhenConvertingToAnArray_ThenReturnsAnArray()
Assert.NotEmpty(result);
}

[Fact]
public void GivenAConcurrentBagFilledOnOneThread_WhenDrainingOnThatThread_ThenReturnsItemsLastInFirstOut()
{
var result = ConcurrentBagDemo.DrainOwnQueue();

Assert.Equal(new List<int> { 5, 4, 3, 2, 1 }, result);
}

[Fact]
public void GivenAConcurrentBagFilledOnOneThread_WhenDrainingOnADifferentThread_ThenReturnsItemsOldestFirst()
{
var result = ConcurrentBagDemo.DrainStolenQueue();

Assert.Equal(new List<int> { 0, 1, 2, 3, 4 }, result);
}

[Fact]
public void GivenAConcurrentBag_WhenClearingAConcurrentBag_ThenReturnsAnEmptyConcurrentBag()
{
var bag = ConcurrentBagDemo.CreateAndAddToConcurrentBagConcurrently();

ConcurrentBagDemo.ConcurrentBagClearMethod(bag);

Assert.True(bag.IsEmpty);
Assert.Empty(bag);
}

[Fact]
public void GivenAConcurrentBag_WhenCopyingToAnArray_ThenReturnsAnArray()
{
Expand Down
10 changes: 5 additions & 5 deletions collections-csharp/ConcurrentBagInCSharp/Tests/Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Loading