dbnex14 dbnex14 - 1 month ago 15
C# Question

Process Tasks in Order

I have number of event notifications happening each time for example a file is added to a folder (this is not my case but just an analogy to explain).

There could be any number of files added to folder, we dont know how many will there be.

Currently, my event myEvent_Handler fires each time a file is added

private void myEvent_Handler(object sender, SomeEvent e)
{
// I dont know how many times this event will fire
if (something == true) (1)
{
var t = Task.Run(() =>
{
DoSomething(e); (2)
});
}
}


The problem in above event handler is the race condition btw line marked with (1) and (2). For example, the event is fired 4 times:


  1. (1) is true, (2) is queued in a task to run

  2. (1) is true, (2) is queued in a task to run

  3. (1) is true, (2) is queued in a task to run

  4. (1) is true, (2) is queued in a task to run



Now, tasks queue has 4 tasks to run but these are not executed in same order. They could execute in any order, i.e. 3->2->4->1 but I need them to execute as 1->2->3->4 without blocking UI thread.

How can I achieve this without blocking UI thread?

Answer

I figured it out and rewrote my code above to do this:

private void myEvent_Handler(object sender, SomeEvent e)
{
  // I dont know how many times this event will fire
  Task t = new Task(() =>
  {
    if (something == true) 
    {
        DoSomething(e);  
    }
  });
  t.RunSynchronously();
}

That is working great and is not blocking my UI thread.

UPDATE: Although I have found that this was working great for me (it fixed my race condition and my UI thread was not blocked), upon further investigation, I found that the method calling this code was not executing on UI thread (which explains why this code was not blocking my UI thread) but checking for ManagedThreadId, I found that the task above was running on same thread on which this method is running. As a result, I changed my implementation according to these 2 posts:

https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx

How (and if) to write a single-consumer queue using the TPL?

to use LimitedConcurrencyLevelTaskScheduler (provided in above MSDN article.

That solution works well, the task is not executing on same thread as the method in which task in instantiated which increases performance.