The Sequencer (part 2.1)


Update

I received two more proposals I will comment soon.

Original

I closed the last episode with a little exercise for my readers: suggest me how to complete my requirements, namely by ensuring guaranteed ordering for the sequencer.

Alas, only two were skilled or brave enough to face the challenge and try an answer, and I thank them for that.

The two proposal were similar, but freeman did provide a gist, so let’s discuss it


using System;
using System.Collections.Generic;
using System.Threading;
namespace Sequencer
{
using System.Collections.Concurrent;
public class Sequencer
{
private readonly ConcurrentQueue<Action> _pendingTasks = new ConcurrentQueue<Action>();
private readonly object _running = new Object();
public void Dispatch(Action action)
{
// Queue the task
_pendingTasks.Enqueue(action);
// Schedule a processing run (may be a noop)
ThreadPool.QueueUserWorkItem( x=> Run());
}
// run when the pool has available cpu time for us.
private void Run()
{
if (Monitor.TryEnter(_running))
{
try
{
Action taskToRun;
while (_pendingTasks.TryDequeue(out taskToRun))
{
taskToRun();
}
}
finally
{
Monitor.Exit(_running);
}
}
}
}
}

view raw

Sequencer_1.cs

hosted with ❤ by GitHub

Definitely, this will capture and secure the order of execution. And I like the smart use of TryEnter, allowing to get rid of the boolean used to store the state

But, and this is a big but, this solution violates another (implicit) requirement. I have to apologize for this one, as I failed to state it earlier.

But you know customers: they understand what they need when the development is over :-).

That requirement is fairness: fairness between Sequencer instances as well as fairness between Sequencers and other tasks. Fairness is to be understood as the guarantee that all submitted tasks will eventually executed,that they have equivalent access to execution units (i.e. cores), and with similar delays.
It means that no system can gain exclusive access to execution unit(s) ans that tasks are executed roughly in the order they are submitted.

This being defined, this solution is not fair. Can you tell me why?

Note: here is a gist for the first proposal

5 thoughts on “The Sequencer (part 2.1)

  1. If a sequencer keeps dispatching actions, the Run method will never end. It is not fair because the sequencer will monopolize a ThreadPool thread. It is also a bad practice to execute long running tasks in the ThreadPool.

    Like

    1. Before Cyrille buy a new laptop (the previous one seems to suffer toi much from his multithreading experimentation;-) and creates the open source project we talked about, I suggest that we continue what I already added on my github, with a first test, and our two Sequencer implementation. https://github.com/tpierrain/SequencerAiiiight/

      Like

Leave a reply to Thomas Pierrain (@tpierrain) Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.