Здравствуйте, 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++"); он никогда не добирается.
А исклю