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

A bench by Myxi, on Flickr
A bench, a photo by Myxi on Flickr.

Visit these posts for Part 1, Part 2, Part 3, Part 4, and implementation!

The real magic starts now…

First of all we will create an example task class (could be any model/view-model class), which is our real world class with the code to be processed on BG thread. The class encapsulates its own behavior.

    public class TypeOneTask
    {
        Random _testWait = new Random();
        public string Name { get; set; }
        public event EventHandler BackgroundProcessFinished;
        public TypeOneTask(string name)
        {
            Name = name;
        }
        public void Process()
        {
            DateTime _st = DateTime.Now;
            Debug.WriteLine("BG Thread : Task {0} Started @ {1}", Name, _st.ToString("hh:mm:ss.fff"));
            Thread.CurrentThread.Join(_testWait.Next(735, 1923));
            Debug.WriteLine("BG Thread : Task {0} Ended @ {1}", Name, DateTime.Now.ToString("hh:mm:ss.fff"));
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (BackgroundProcessFinished != null)
                {
                    BackgroundProcessFinished(this, new EventArgs());
                }
            });
        }
    }

This is a simple example class with a Name property and Process method. The process method has Debug messages and Thread.Join to simulate process. On completion of the process, the method fires an event on the dispatcher thread, i.e. the UI thread.

We will also need an equality comparer, to avoid duplicate objects being queued for process. Currently we will simply compare the reference, but equating could be extended in real world classes.

    public class TypeOneTaskEqualityComparer : IEqualityComparer<TypeOneTask>
    {
        public bool Equals(TypeOneTask A, TypeOneTask B)
        {
            if (A != null && B != null)
            {
                return A == B;
            }
            else
            {
                return false;
            }
        }
        public int GetHashCode(TypeOneTask itm)
        {
            return itm.GetHashCode();
        }
    }

Now comes the implementation of our generic ConcurrentQueue class by inheriting in a new class named TaskOneQueue. We will implement the required method/properties in the derived class and in the ProcessRequest method, which is protected and called from the base class, we will call the TypeOneTask’s process method. This is the actual process which runs on the background thread. So here is the code for our TaskOneQueue:

   public class TaskOneQueue : ConcurrentQueue<TypeOneTask>
    {
        #region queue implementationsc
        TypeOneTaskEqualityComparer _itemEqualityComparer = new TypeOneTaskEqualityComparer();
        public override bool IsQueueAlive
        {
            get
            {
                return base.IsQueueAlive;
            }
        }
        public override IEqualityComparer<TypeOneTask> QueueItemEualityComparer
        {
            get
            {
                return _itemEqualityComparer;
            }
        }
        public override bool IsQueueAvailableForEnqueue()
        {
            if (this.Count > 20)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        protected override void ProcessRequest(TypeOneTask taskRequest, bool Async)
        {
            taskRequest.Process();
        }
        public override void Exit(bool discardPendingRequests)
        {
            base.Exit(discardPendingRequests);
        }
        public override void DoWhenQueueGetsEmpty()
        {
            //doing nothing
        }
        #endregion
    }

We have our structure taken care of. Let’s put this things in a example form to see how things work. We will create a simple Windows Phone project and in the default MainPage.xaml’s ContentPanel element, we will put a StackPanel containing three buttons:

      <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
        	    <Button Content="Button" Height="69" Margin="110,49,127,0" VerticalAlignment="Top" Click="Button_Click"/>
                <Button Name="buttonDummy1" Content="Dummy 1" Height="69" Margin="110,49,127,0" VerticalAlignment="Top" Click="buttonDummy1_Click" />
                <Button Name="buttonDummy2" Content="Dummy 2" Height="69" Margin="110,49,127,0" VerticalAlignment="Top"  Click="buttonDummy2_Click"/>
            </StackPanel>
        </Grid>

Code behind for this form looks like this:

   public partial class MainPage : PhoneApplicationPage
    {
        TaskOneQueue t1Queue = new TaskOneQueue();
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            this.BackKeyPress += new EventHandler<System.ComponentModel.CancelEventArgs>(MainPage_BackKeyPress);
        }

        void MainPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            t1Queue.Exit(true);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TypeOneTask _t1 = new TypeOneTask("Type1 Task - 1");
            TypeOneTask _t2 = new TypeOneTask("Type1 Task - 2");
            TypeOneTask _t3 = new TypeOneTask("Type1 Task - 3");
            _t2.BackgroundProcessFinished += new EventHandler(_t2_BackgroundProcessFinished);
            _t3.BackgroundProcessFinished += new EventHandler(_t3_BackgroundProcessFinished);

            Debug.WriteLine("UI Thread : Task enqueue start");
            t1Queue.Process(_t1, true, false);
            t1Queue.Process(_t2, true, false);
            t1Queue.Process(_t3, true, false);
            Debug.WriteLine("UI Thread : Task enqueue finished. Enqueued Type1 tasks 1, 2, and 3. UI thread is free");
        }

        void _t3_BackgroundProcessFinished(object sender, EventArgs e)
        {
            Debug.WriteLine("UI Thread : All tasks are over!");
        }

        void _t2_BackgroundProcessFinished(object sender, EventArgs e)
        {
            Debug.WriteLine("UI Thread : Task two has finished and UI thread got the message!");
        }

        private void buttonDummy1_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("UI Thread : Dummy button 1 clicked!");
        }

        private void buttonDummy2_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("UI Thread : Dummy button 2 clicked!");
        }

    }

In the code above, we have defined TaskOneQueu type object – t1Queue. In Button_Click event handler we are enqueuing three TypeOneTasks and at the start and end of enqueuing, sending output to Debug window. This shows that UI thread gets free after enqueuing the tasks. This is further demonstrated in the click handlers of the buttonDummy1_Click and buttonDummy2_Click, which you can manually click at run time to see that UI thread is free and task processes are happening in the background. When we run this form in Debug mode, and click the first button and then subsequently Button 2 and Button 3 at 1-2 seconds apart, we get following output from Debug. You can see when UI thread gets free and first TypeOneTask starts processing. In the mean time the two dummy buttons are also clicked and their click events got registered successfully without having any impact on the background processes.

Output.Debug
UI Thread : Task enqueue start
UI Thread : Task enqueue finished. Enqueued Type1 tasks 1, 2, and 3. UI thread is free
BG Thread : Task Type1 Task - 1 Started @ 04:39:24.483
UI Thread : Dummy button 1 clicked!
BG Thread : Task Type1 Task - 1 Ended @ 04:39:26.436
BG Thread : Task Type1 Task - 2 Started @ 04:39:26.442
UI Thread : Dummy button 2 clicked!
BG Thread : Task Type1 Task - 2 Ended @ 04:39:28.258
BG Thread : Task Type1 Task - 3 Started @ 04:39:28.264
UI Thread : Task two has finished and UI thread got the message!
BG Thread : Task Type1 Task - 3 Ended @ 04:39:30.090
UI Thread : All tasks are over!

In the last post we will create one more queue and run multiple queues simultaneously to see things in action.

continued…part 6

Advertisements

4 thoughts on “C#|.NET : Generic Concurrent Queue (5/6)

  1. Pingback: C#|.NET : Generic Concurrent Queue (4/n) | Sharp Statements

  2. Pingback: Dew Drop – February 21, 2014 (#1728) | Morning Dew

  3. Pingback: Dew Drop – February 24, 2014 (#1729) | Morning Dew

  4. Pingback: C#|.NET : Generic Concurrent Queue (6/6) | Sharp Statements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s