Re[4]: Interlocked
От: RushDevion Россия  
Дата: 29.12.18 10:32
Оценка: 3 (1)
RA>Большое спасибо за пример. Основную идею я понял. В посте ниже справедливо указали, на то, что моя реализация не отвечает заявленным критериям, а именно при возникновении ошибки при получении значения ожидающие потоки не получат тот же объект исключения. Сейчас набросал небольшой тест кейс и думаю как модифицировать мою реализацию. Пока безуспешно.
Как идея: можно возвращать Task. Тогда проброс ошибок будет автоматическим.
public class Lazy<T>
{
    private Task<T> m_Value;
    private readonly Func<Task<T>> m_Factory;

    public Lazy(Func<Task<T>> factory) { m_Factory = factory; }

    public Task<T> GetValueAsync()
    {
        // Запускаем инициализацию
        Interlocked.CompareExchange(ref m_Value, m_Factory(), null);
        var task = Volatile.Read(ref m_Value);
        
        // Ошибка инициализации? Сбросим текущую таску в null, чтобы перезапуститься при след. обращении
        task.ContinueWith(_ =>
                Interlocked.CompareExchange(ref m_Value, null, task),
            TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);

        return task;
    }
}



RA>На сколько понимаю это связано из-за ограничения методов Volatile.* Это можно как то обойти?

Да, Volatile работает с очень ограниченным набором типов.
Ну можно использовать вложенный класс, типа такого:
public class Lazy<T>
{
    private ValueHolder m_ValueHolder;
    private Func<T> m_Factory;

    private  class ValueHolder
    {
        public T Value;
    }

    private T Value
    {
        get
        {
            Interlocked.CompareExchange(ref m_ValueHolder, new ValueHolder {Value = m_Factory()}, null);
            var holder = Volatile.Read(ref m_ValueHolder);
            return holder.Value;
        }
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.