Re[9]: SynchronizationContext a-la node.js
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.10.16 15:02
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Serginio1, Вы писали:


S>> Там пример на ConfigureAwait(false) для библиотек для того, что бы они не вызываличь в потоке UI.

S>Эта ошибка с любым лимитированным шедулером возможна, просто понадобится больше ожидающих задач.
S>Лечить надо причину, а не симптомы.

S>>Лучше бы сделали наоборот, сто по умолчанию ConfigureAwait(false)

S>Как обычно: предлагаем что-то — не останавливаемся,а думаем "а что, если моё пожелание сбудется?". Дальше продолжать?


S>>Так все await последовательно будут выполняться. Только после того когда они все закончатся будет вызван Take()

S>>Другое дело если внутри есть ContinueWith или Task.Run
S>Речь про произвольный код — по определению на это надо закладываться.


S>> Давай конкретный пример разберем. И в каком месте здесь дедлок


S>ну это ж классика. Самый простой способ:

S>
  что не так-то?
S>
S>public class AsyncProducerConsumerCollection<T>
S>{
S>    private readonly Queue<T> m_collection = new Queue<T>();

S>    private readonly Queue<TaskCompletionSource<T>> m_waiting =
S>        new Queue<TaskCompletionSource<T>>();

S>    public void Add(T item)
S>    {
S>        TaskCompletionSource<T> tcs = null;
S>        lock (m_collection)
S>        {
S>            if (m_waiting.Count > 0)
S>                tcs = m_waiting.Dequeue();
S>            else
S>                m_collection.Enqueue(item);
S>        }
S>        if (tcs != null)
S>            tcs.TrySetResult(item);
S>    }

S>    public Task<T> Take()
S>    {
S>        lock (m_collection)
S>        {
S>            if (m_collection.Count > 0)
S>            {
S>                return Task.FromResult(m_collection.Dequeue());
S>            }
S>            else
S>            {
S>                var tcs = new TaskCompletionSource<T>();
S>                m_waiting.Enqueue(tcs);
S>                return tcs.Task;
S>            }
S>        }
S>    }
S>}

S>static class Program
S>{
S>    private static AsyncProducerConsumerCollection<Action> m_data = new AsyncProducerConsumerCollection<Action>();

S>    private static async Task ConsumerAsync()
S>    {
S>        while (true)
S>        {
S>            var nextItem = await m_data.Take();
S>            nextItem.Invoke();
S>        }
S>    }

S>    private static void Produce(Action data)
S>    {
S>        m_data.Add(data);
S>    }

S>    static void Main(string[] args)
S>    {
S>        var local1 = 0;
S>        Action a = null;
S>        a = () =>
S>        {
S>            while (local1 == 0)
S>            {
S>                Produce(
S>                    () =>
S>                    {
S>                        Console.WriteLine(">local1++");
S>                        local1++;
S>                        Produce(a);
S>                    });
S>            }
S>            Console.WriteLine("!!!" + local1);
S>        };

S>        Produce(a);
S>        ConsumerAsync().Wait();

S>        Console.WriteLine("Done.");
S>        Console.ReadKey();
S>    }
S>}
S>




Посмотрел.

Правильнее по алгоритму сначала запустить чтение

ConsumerAsync();

А затем вставку
Produce(a);



while (local1 == 0)
            {
// Просто запускает делегат
// А он не выполнится пока ConsumerAsync() не сработает
// А он в твоем алгоритме стоит поле Produce
// И цикл крутится бесконечно
                Produce(
                () =>
                    {
                        Console.WriteLine(">local1++");
                        local1++;
                        Produce(a);
                    });
            }


Но и в случае с ConsumerAsync() он вызывает Produce с тем же бесконечным циклом и ждет выполнения.
При этом до Console.WriteLine(">local1++"); он никогда не добирается.

А исклю
и солнце б утром не вставало, когда бы не было меня
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.