Task and ConcurrentQueue

In this blog, I will create a sample to demo the usage of Task and ConcurrentQueue. Task allows us to represent an asynchronous operation. ConcurrentQueue is a FIFO data structure similar to Queue, however, it is thread-safe. Thread-safe means that we will not have undesirable results in case multiple threads operate over this data structure.

First, let's see the code sample:
In the main method, we are creating 4 tasks. 1 for producing (adding items to the queue) and 3 others for consuming (removing items from the queue). The StartNew() argument for Task takes an Action delegate item. By calling the WaitAll() method we direct the main thread to wait until all the threads have completed. We can also call the RunSynchronously() method on a task to make it run in the main thread rather than in a new thread.

In the ProduceTasks() method, we just line up 10 items in the queue. The QueueObject is created just to keep track of what the Queue is doing, so that we can display the details later.

In the ConsumeTasks() method, we call the TryDequeue() method to remove items from the queue. I use the QueueObject's DecimalPlaces property to calculate the value of pi. This gives me a real time consuming operation compared to using Thread.Sleep. You can download the pi calculation code from this link: http://www.boyet.com/articles/picalculator.html

Once the value of pi is calculated, we print the results on the console. The results are displayed below:


As you can see, Main Thread id is 9, while the enque (Task1) happened on thread 10. The Deque operation happened (Task2, Task3, Task4) across 3 thread 11, 12 and 13. The 3rd column shows the end time and the 4th column shows the number of decimal places pi was calculated to.

Similar to this, we can implement ConcurrentStack with pop and push operations.