32

await はスレッドセーフですか? Task クラスはスレッドセーフのようですので、それを待っているのもスレッドセーフだと思いますが、どこにも確認が見つかりませんでした。また、スレッド セーフはカスタム awaiter の要件です。つまり、IsCompleted、GetAwaiter などのメソッドですか? つまり、これらのメソッドがスレッド セーフでない場合、await はスレッド セーフになりますか? ただし、すぐにカスタム awaiter が必要になるとは思いません。

ユーザー シナリオの例: 結果を非同期に返すバックグラウンド タスクがあり、それが複数のスレッドから使​​用されるとします。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace scratch1
{
    class Foo
    {
        Task<int> _task;

        public Foo()
        {
            _task = Task.Run(async () => { await Task.Delay(5000); return 5; });
        }

        // Called from multiple threads
        public async Task<int> Bar(int i)
        {
            return (await _task) + i;
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            Foo foo = new Foo();

            List<Task> tasks = new List<Task>();
            foreach (var i in Enumerable.Range(0, 100))
            {
                tasks.Add(Task.Run(async () => { Console.WriteLine(await foo.Bar(i)); })); 
            }

            Task.WaitAll(tasks.ToArray());
        }
    }
}
4

1 に答える 1

20

あなたがほのめかしたように、awaitそもそもスレッドが見えないほど薄いです。

関連するコードawait(ステート マシン内のコンパイラ生成コード、および BCL 内のサポート クラス) は、一度に 1 つのスレッドでのみ実行されます。(待機可能から戻ったときに別のスレッドに切り替えることができますが、前の実行は既に終了しています)

実際のスレッド セーフは、待機しているオブジェクトによって異なります。
コールバックを追加するには、スレッドセーフな方法が必要です (またはawait、一度に 2 回実行すると壊れる可能性があります)。

さらに、コールバックを 1 回だけ呼び出す必要があります。そうしないと、ステート マシンが壊れる可能性があります。(特に、同時に 2 つのスレッドでコールバックを実行すると、事態はひどく悪化します)

Taskスレッドセーフです。

于 2013-05-29T17:34:19.783 に答える