0

私は新しい C# の await 機能を試していました。次のようにカスタム awaiter 実装を作成しました。

using System;
using System.Runtime.CompilerServices;
using System.Threading;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            T1();
            Console.WriteLine("After t1");
        }

        private static async void T1()
        {
            CustomAwaitable a = new Sleeper().Sleep();
            object r = await a;
            Console.WriteLine("sleeper awakes " + r);
        }
    }

    internal class CustomAwaitable
    {
        private readonly Sleeper m_sleeper;

        public CustomAwaitable(Sleeper s)
        {
            m_sleeper = s;
        }

        public MyAwaiter GetAwaiter()
        {
            return new MyAwaiter(m_sleeper);
        }
    }

    internal class Sleeper
    {
        public ManualResetEvent Handle = new ManualResetEvent(false);

        public bool Awake { get; set; }

        public int Result
        {
            get { return Environment.TickCount; }
        }

        public CustomAwaitable Sleep()
        {
            new Thread(() =>
            {
                Thread.Sleep(5000);
                Awake = true;
                Handle.Set();
            }).Start();
            Console.WriteLine("begin sleeping " + Result);
            return new CustomAwaitable(this);
        }
    }

    internal class MyAwaiter : INotifyCompletion
    {
        private readonly Sleeper m_sleeper;

        public MyAwaiter(Sleeper sleeper)
        {
            m_sleeper = sleeper;
        }

        public bool IsCompleted
        {
            get { return m_sleeper.Awake; }
        }

        public void OnCompleted(Action continuation)
        {
            // This works!!
            //new Thread(() => 
            //{
            //  m_sleeper.Handle.WaitOne();
            //  continuation();
            //}).Start();

            // This doesn't work!!
            Action k = () =>
            {
                m_sleeper.Handle.WaitOne();
                continuation();
            };

            k.BeginInvoke(null, null);
        }

        public object GetResult()
        {
            return m_sleeper.Result;
        }
    }
}

問題は、OnCompleted メソッドで、BeginInvoke を使用して継続コードの実行をスケジュールすると、GetResult メソッドが呼び出されないことです。しかし、同じことを行うために手動でスレッドを作成すると、すべてが期待どおりに機能します。BeginInvoke はスレッド プールを内部的に使用することを知っています。これは、スレッド アプローチと同じように機能するはずです (スレッド プールにはスレッド数の制限があることはわかっていますが、この場合は他に何も実行していないため無視できます)。

あなたのアイデアは何ですか?ありがとう!

4

0 に答える 0