個人的備忘録

調べたり思いついたりした事の置き場

独自SynchronizationContextの実装

独自のスレッドでasync/awaitしたかったので、SynchronizationContextを実装する。

class SingleThreadSynchronizationContext : SynchronizationContext
{
    BlockingCollection<Action> queue = new BlockingCollection<Action>();
    Thread thread;

    public SingleThreadSynchronizationContext()
    {
        thread = new Thread(Run);
        thread.Start();
    }

    void Run()
    {
        SynchronizationContext.SetSynchronizationContext(this);
        try
        {
            while (true)
            {
                var action = queue.Take();
                action();
            }
        }
        catch (InvalidOperationException)
        {
            // Complete
        }
    }
    public void Stop()
    {
        queue.CompleteAdding();
        thread.Join();
    }

    Task Exec(Action func)
    {
        var task = new TaskCompletionSource<object>();
        queue.Add(() =>
        {
            try
            {
                func();
                task.SetResult(null);
            }
            catch (Exception e)
            {
                task.SetException(e);
            }
        });
        return task.Task;
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        Exec(() => d(state));
    }

    public override void Send(SendOrPostCallback d, object state)
    {
        Exec(() => d(state)).Wait();
    }

    public override SynchronizationContext CreateCopy()
    {
        return this;
    }
}

こんな感じでasync/awaitが動作した。
Post、Send、CreateCopyあたりをオーバーライドすれば良いらしい。