HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Simple dispatcher implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationsimpledispatcher

Problem

I need a simple dispatcher implementation(invoke methods on one thread from many threads)
once you dispatch method curent thread should wait for results, so I'm thinking about something like this:

public class Dispatcher
{
    private readonly BlockingCollection> runQueue = new BlockingCollection>();
    private readonly BlockingCollection resultQueue = new BlockingCollection();
    private readonly CancellationTokenSource source = new CancellationTokenSource();
    private readonly Task task;
    public Dispatcher()
    {
        Task.Run(() =>
        {
            using (source)
            using (runQueue)
            using (resultQueue)
            {
                Debug.WriteLine("Dispatcher started with thread {0}", Thread.CurrentThread.ManagedThreadId);
                while (!source.IsCancellationRequested)
                {
                    var run = runQueue.Take(source.Token);
                    resultQueue.Add(run.Item1.DynamicInvoke(run.Item2));
                }
                Debug.WriteLine("Dispatcher ended");
            }
        });
    }

    public void Stop()
    {
        source.Cancel();
    }

    [MethodImpl(MethodImplOptions.Synchronized)]
    public object Invoke(Delegate @delegate, params object[] @params)
    {
        runQueue.Add(new Tuple(@delegate, @params));
        return resultQueue.Take(source.Token);
    }
}


I had test it with such code and it seems too work well ...

```
class Program
{
static void Main(string[] args)
{
Func func = (sleep, i) =>
{
CC.WriteLine(i, "\tTask {0} will sleep for {1}, thread {2}", i, sleep, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(sleep);
CC.WriteLine(i, "\tTask {0} woke up", i, sleep);
return i; //return task number
};
var rnd = new Random();
var disp = new Dispatcher();
{
var tasks = Enumerable.Range(0, 10).Select(i =>
Task.Ru

Solution


  • Because the task within the Dispatcher is a long running task, you should use the option TaskCreationOptions.LongRunning. Otherwise the operation blocks a thread-pool thread that is usually used for short operations. Alternatively you could also use a Thread.



  • Instead of using the blocking collection for returning the result, you could use a TaskCompletionSource. That would change the return value of the method Invoke to Task. Therfore the calling code could use the async/await-pattern.



  • Consider to throw an exception if the Dispatcher was stopped and Invoke is called. Otherwise the call blocks forever, right?

Context

StackExchange Code Review Q#134870, answer score: 8

Revisions (0)

No revisions yet.