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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
| 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); | |
| } | |
| } | |
| } | |
| } | |
| } |
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
