2

I've been investigating SynchronizationContext and these articles (Understanding SynchronizationContext, ExecutionContext vs SynchronizationContext) really helped me along, but - of course - many questions remain.

I would like to implement my own SynchronizationContext class that inherits from the base class so that I can use it in the context of any Task (for custom message loops, throttling, tracking etc.); something like this:

public class SyncContext : System.Threading.SynchronizationContext
{

    public SyncContext() : base()
    {
    }

    public override void Send(Threading.SendOrPostCallback d, object state)
    {
        base.Send(d, state);
    }

    public override void Post(Threading.SendOrPostCallback d, object state)
    {
        base.Post(d, state);
    }
}

While base.Send appears to do what expected (execute the callback synchronously), base.Post doesn't appear to do anything. Regarding the Post method Microsoft states:

When overridden in a derived class, dispatches an asynchronous message to a synchronization context.

I guess the base class can't be blamed for not having an async mechanism implemented, but what should happen when base.Post is called or how could a correct/better implementation look? Is my general approach already misleading?

Thanks for your efforts!

A follow-up question: Would implementing a custom TaskScheduler maybe be a better approach - maybe TaskScheduler that uses a dedicated thread is essentially what I need?

Community
  • 1
  • 1
mike
  • 1,627
  • 1
  • 14
  • 37
  • That is the crux of a SynchronizationContext, nothing else matters. If you don't know how to write it then you can't implement one. It must get the `d` code to run on another **specific** thread. Such a thread must solve the [producer-consumer problem](https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem). A dispatcher loop like Winforms or WPF or UWP uses is the standard solution. – Hans Passant Feb 23 '16 at 13:50
  • @Hans: I think I've successfully implemented a message loop with a blocking queue, but now I'm looking for a wrapper I can put in. I was just wondering what the use of the Post method is as implemented in the SynchronizationContext base class, i.e. why wasn't it declared abstract? – mike Feb 23 '16 at 14:01
  • It is not abstract because SychronizationContext knows how to implement it. By not synchronizing anything, the delegate runs on a threadpool thread. Not useful, you'll have to override it, your Post() method simply needs to add the delegate to that queue. The Send() method must do the same thing *and* wait for the queue entry to be consumed. This requires, say, an AutoResetEvent to be included with the queue entry. Do keep in mind that you are re-inventing existing .NET SychronizationContext implementations, like the kind used by [this code](http://stackoverflow.com/a/21684059/17034). – Hans Passant Feb 23 '16 at 14:20
  • @Hans: Thanks for your patience and helping me along! What I still don't understand is why a delegate is never executed, if passed to `base.Post`. And, yes, I (kind of, I guess) know I'm trying to re-invent the wheel ;o). – mike Feb 23 '16 at 14:42
  • Is there any point in anybody trying to find out what is wrong with that code snippet you posted? Without seeing how you use it? It completely doesn't do what you need it to do so that is just wasted time. – Hans Passant Feb 23 '16 at 14:51

1 Answers1

0

If you have your own Message Loop, then it needs to be captured in the SynchronizationContext, so when another thread calls SynchronizationContext.Post - the callback action must be added to that Message Loop.

The SynchronizationContext "flows" as a part of ExecutionContext, but not always, so you need to take care of that flow in the code (if possible).

The default implementation of the Post method is queuing the action on a worker thread (got with ILSpy):

public virtual void Post(SendOrPostCallback d, object state)
{
  ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);
}

But the big question is why do you need your own SynchronizationContext? If it's just for fun - that's fine, otherwise you are doing smth very advanced, and maybe other existing more simpler mechanisms can solve the problem.

Serge Semenov
  • 9,232
  • 3
  • 23
  • 24