C#|.NET : Generic Concurrent Queue (6/6)

In this concluding post we will make some changes to further separate some concerns and see multiple queues in action. First we will take the queue initialization to higher level in availability and define the queues in our top level class, i.e. App.xaml.cs. This way our queues are available everywhere in the application. We will move out background enqueue-ing to class level and expose it through a method. This is to encapsulate the behavior to self-enqueue-ing in the class itself. So the user of the class does not have to know anything about the queue, they could simply call the class’ method and the class will queue itself for background work. Let’s start.
First, let’s modify the code of TypeOneTask class we created in Part 5, and encapsulate enqueue behavior in the class itself. We will introduce a new public method QueueInForBackgroundWork:

Before going to consumption code for this method in our main page’s code behind, let’s first set-up TypeTwoTask class and a new queue for the same. We will create a new class file TaskTwoQueue.cs and write code in this file. Most of the code in these classes is similar to what we created in Part5, so I will write all the code in one code block:

We are ready with our second queue. We will introduce this queue in our application at the application level. In app.xaml.cs we will define both the queues like so (mind that both the queues are static):

The final user of our two classes, the main page, now, does not need to know about the queue (for previous code see part 5). It will only define the fields of appropriate task type, and call its QueuInForBackgroundWork as and when required. To demonstrate this behavior, we will modify MainPage.xaml.cs. We will first define 3 tasks of both the types at the page level. We will then have event handlers for both the types of the tasks to have informed about the completion of the task on UI thread. Button_click enqueues TypeOneTask in the queue by calling QueueInForBackgroundWork method and buttonDummy1_Click does the same for TypeTwoTask. Here is the code:

When you run the the app in debug mode, you get three buttons – Button1, dummy 1, and dummy 2, same as we had in part 5. This time Button1 and dummy 1 both enqueue tasks and dummy 2 is just to demonstrate that UI thread is free. Now, with 1-2 seconds delay, click on these three buttons top to bottom. You will get following log in your Debug output:

The analysis of this output shows that Type1 tasks were enqueued first, because I clicked Button1 first, and as soon as all three tasks are enqueued UI thread was freed. Also, “Task Type1 Task-1” started its BG work. Because UI was free, after two seconds, I clicked Dummy 1 button which enqueued all the three tasks of TypeTwoTask in its queue. Both these queues are working on their own background threads. UI thread is completely free. When tasks get over UI gets a message.

To summarize, Generic Concurrent Queue has following characteristics:

Generic and abstract, to be inherited to implement for any type.

Process requests can be queued up for BG thread.

Has a single lazy-init BG thread.

Supports sync and async requests.

By supplying a sync process request, you can stop other processes in queue and have sync request process first. Queue resumes automatically after the sync task is over.

Queue can be paused and restarted as and when required.

Queue can be exited | killed as and when required.

Inherited class defines rules for Queue capacity.

Inherited class defines rules for process request duplicate value.

Uses basic lock/wait/pulse mechanism, so compatible with almost all variants of .NET