32

等待线程安全吗?似乎 Task 类是线程安全的,所以我想等待它也是线程安全的,但我没有在任何地方找到确认。线程安全也是自定义等待器的要求 - 我的意思是 IsCompleted、GetAwaiter 等方法?即,如果这些方法不是线程安全的,那么 await 会是线程安全的吗?但是,我不希望很快需要自定义等待者。

用户场景示例:假设我有一个异步返回结果的后台任务,然后从多个线程中使用:

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 中的支持类)相关的代码一次只能在一个线程上运行。(从等待返回时可以切换到不同的线程,但之前的运行已经完成)

实际的线程安全取决于您正在等待的对象。
它必须有一种线程安全的方式来添加回调(或者await一次 ing 两次可能会中断)。

此外,它必须只调用一次回调,否则可能会破坏状态机。(特别是,如果它同时在两个线程上运行它的回调,事情会变得非常糟糕)

Task是线程安全的。

于 2013-05-29T17:34:19.783 回答