简体   繁体   English

可以从多个线程等待相同的任务 - 等待线程安全吗?

[英]Is it ok to await the same task from multiple threads - is await thread safe?

Is await thread safe? 等待线程安全吗? It seems the Task class is thread safe so I guess awaiting it is also thread safe but I haven't found a confirmation anywhere. 似乎Task类是线程安全的,所以我猜等待它也是线程安全的,但我还没有在任何地方找到确认。 Also is thread safety a requirement for custom awaiter - I mean for the IsCompleted, GetAwaiter, etc. methods? 线程安全也是定制awaiter的要求 - 我的意思是IsCompleted,GetAwaiter等方法? Ie if those methods are not thread safe, will await be thread safe? 即如果这些方法不是线程安全的,那么等待是否是线程安全的? However, I don't expect needing a custom awaiter anytime soon. 但是,我不希望很快就需要定制的等待者。

An example of user scenario: Let's say I have a background task which returns a result asynchronously, which is then used from multiple threads: 用户场景的一个示例:假设我有一个后台任务,它以异步方式返回结果,然后从多个线程使用:

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());
        }
    }
}

As you alluded to, await is thin enough that it doesn't see threads in the first place. 正如你所提到的那样, await足够薄,以至于它首先看不到线程。

The code associated with await (the compiler-generated code within the state machine, and the support classes in the BCL) will only ever run on one thread at a time. await相关联的代码(状态机中的编译器生成的代码以及BCL中的支持类)将一次只能在一个线程上运行。 (it can switch to a different thread when coming back from the awaitable, but the previous run will have already finished) (它可以在从等待状态返回时切换到不同的线程,但之前的运行已经完成)

The actual thread-safety depends on the object you're awaiting. 实际的线程安全性取决于您正在等待的对象。
It must have a thread-safe way to add callbacks (or await ing it twice at once may break). 它必须具有线程安全的方式来添加回调(或者await它一次两次可能会中断)。

In addition, it must call the callback exactly once, or it may break the state machine. 此外,它必须只调用一次回调,否则可能会破坏状态机。 (in particular, if it runs its callback on two threads at the same time, things will go horribly wrong) (特别是,如果它同时在两个线程上运行它的回调,事情会发生可怕的错误)

Task is thread-safe. Task是线程安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM