Подтвердить что ты не робот

Можно ли ждать одной задачи из нескольких потоков - ждать потокобезопасности?

Ожидает ли поток безопасности? Кажется, класс Task является потокобезопасным, поэтому я ожидаю, что он также потокобезопасен, но я нигде не нашел подтверждения. Также существует проблема безопасности потоков для пользовательского awaiter - я имею в виду методы IsCompleted, GetAwaiter и т.д.? То есть если эти методы не являются потокобезопасными, ожидают потокобезопасности? Тем не менее, я не ожидаю, что в ближайшее время вам понадобится пользовательский 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());
        }
    }
}
4b9b3361

Ответ 1

Как вы уже упоминали, await достаточно тонкий, чтобы он не видел потоков в первую очередь.

Код, связанный с await (код, сгенерированный компилятором в конечном компьютере и классы поддержки в BCL), будет выполняться только по одному потоку за раз. (он может переключиться на другой поток при возврате с ожидаемого, но предыдущий запуск уже завершен)

Фактическая безопасность потока зависит от объекта, который вы ожидаете.
Он должен иметь потокобезопасный способ добавления обратных вызовов (или await одновременное его одновременное прерывание).

Кроме того, он должен вызывать обратный вызов ровно один раз, или он может прервать конечный автомат. (в частности, если он выполняет обратный вызов на двух потоках одновременно, все будет идти ужасно неправильно)

Task является потокобезопасным.