1. Overview:
The namespace provides multiple thread-safe collection classes.
When multiple threads access the collection concurrently, these classes should be used instead of the corresponding types in the namespace.
In order to provide thread-safe access to the collection, the IProducerConsumerCollection interface is defined. The most important methods in this interface are TryAdd() and TryTake().
- The TryAdd() method tries to add an item to the collection, but if the collection prohibits adding items, this operation may fail. To give relevant information, the TryAdd() method returns a Boolean value to indicate whether the operation succeeds or fails.
- The TryTake() method also works this way to inform the caller whether the operation is successful or failed, and returns items in the collection when the operation is successful.
2. Classes contained in the space
ConcurrentXXX: These collections are thread-safe, and if an action does not apply to the current state of the thread, they return false. Before continuing, you must always confirm whether the addition or extraction of elements is successful. You cannot trust that the assembly will complete the task.
1. ConcurrentQueue Queue
This collection class is implemented using a lock-free algorithm, using a 32-item array that is internally merged into a linked list.
Methods to access queue elements are Enqueue(), TryDequeue() and TryPeek(). The naming of these methods is very similar to the methods of the previous Queue class, but the prefix Try is given to methods that may fail to call.
Because this class implements the IProducerConsumerCollection interface, the TryAdd() and TryTake() methods only call the Enqueue() and TryDequeue() methods.
2. ConcurrentStack Stack
Very similar to the ConcurrentQueue class, just with another element access method.
The ConcurrcntStack class defines Push(), PushRange(), TryPeek(), TiyPop(), and TryPopRange() methods. Inside this class uses a linked list of its elements.
3. ConcurrentBag Package
This class does not define any order of adding or extracting items. This class uses a concept that maps threads to arrays used internally, so it tries to reduce locking.
Methods to access elements include Add(), TryPeek() and TryTake().
4. ConcurrentDictionary Dictionary
——This is a thread-safe key-value collection.
The TryAdd(), TryGetValue(), TryRemove(), and TryUpdate() methods access members in a non-blocking manner.
Because elements are based on keys and values, ConcurrentDictionary does not implement IProducerConsumerCollection.
5. BlockingCollection
This collection blocks the thread and waits for the time being before elements can be added or extracted.
The BlockingCollection collection provides an interface to add and delete elements using the Add() and Take() methods. These methods will block the cold thread until the task can be executed.
The Add() method has an overloaded version, where a CancellationToken token can be passed to the overloaded version.
This token allows canceling blocked calls. If you do not want the thread to wait indefinitely and do not want to cancel the call from outside, you can use the TryAdd() and TryTake() methods, in which you can also specify a timeout value that indicates the maximum time that the thread should be blocked and waited before the call fails.
6. BlockingCollection Blocking Collection
This is a modifier for any class that implements the IProducerConsumerCollection interface, which uses the ConcurrentQueue class by default.
You can also pass any other class that implements the IProducerConsumerCollection interface to the constructor.
The following code example briefly demonstrates the process of using the BlockingCollection class and multiple threads.
One thread is a generator, which uses the Add() method to write elements to the collection, and the other thread is a user, which uses the Take() method to extract elements from the collection:
internal static BlockingCollection<int> _TestBCollection; class ThreadWork1 // Producer{ public ThreadWork1() { } public void run() { ("ThreadWork1 run { "); for (int i = 0; i < 100; i++) { ("ThreadWork1 producer: " + i); _TestBCollection.Add(i); } _TestBCollection.CompleteAdding(); ("ThreadWork1 run } "); } } class ThreadWork2 // Consumer{ public ThreadWork2() { } public void run() { int i = 0; int nCnt = 0; bool IsDequeuue = false; ("ThreadWork2 run { "); while (!_TestBCollection.IsCompleted) { IsDequeuue = _TestBCollection.TryTake(out i); if (IsDequeuue) { ("ThreadWork2 consumer: " + i * i + " =====" + i); nCnt++; } } ("ThreadWork2 run } "); } } static void StartT1() { ThreadWork1 work1 = new ThreadWork1(); (); } static void StartT2() { ThreadWork2 work2 = new ThreadWork2(); (); } static void Main(string[] args) { Task t1 = new Task(() => StartT1()); Task t2 = new Task(() => StartT2()); _TestBCollection = new BlockingCollection<int>();//Can be related to capacity ("Sample 4-4 Main {"); ("Main t1 t2 started {"); (); (); ("Main t1 t2 started }"); ("Main wait t1 t2 end {"); (t1, t2); ("Main wait t1 t2 end }"); ("Sample 4-4 Main }"); }
This is all about this article about the Concurrent class of C# concurrent collections. I hope it will be helpful to everyone's learning and I hope everyone will support me more.