Собственная потокобезопасная реализация Lazy<T>
От: RAza  
Дата: 26.12.18 12:11
Оценка:
Приветствую.

Хочу спроектировать тип аналогичный типу Lazy<T> или другими словами предоставляющий функционал аналогичный следующему сниппету:

private T? value = default;
 
public T Value
{
    get
    {
        if (value.HasValue)
            return value.Value;

        return (value = ...).Value;
    }
    set
    {
        this.value = value;
    }
}


Цели, которые я преследую:

    1. Поведение данного типа при доступе к экземпляру из нескольких конкурентных потоков аналогично поведению типа Lazy<T> при использовании режима LazyThreadSafetyMode.ExecutionAndPublication за исключением того, что исключения полученные при использовании фабричного метода НЕ будут кэшированы. Таким образом только один конкурентный поток попытается создать экземпляр указанного типа; при успешном создании все ожидающие потоки получат одинаковое значение; если во время создания возникает необработанное исключение, оно будет повторно создано для каждого ожидающего потока, но оно не будет кэшироваться, и последующие попытки получить доступ к значению повторят попытку создания и могут быть успешными.
    2. Тип является потокобезопасным

public class MyLazy<T>
{
    private readonly Func<T> getAction = null;

    private readonly object obj = new object();

    private readonly bool canBeReseted = false;

    private bool isExist = false;

    private T value = default;

    public bool HasValue => isExist;

    public T Value
    {
        get
        {
            if (Volatile.Read(ref isExist))
                return value;

            lock (obj)
            {
                if (Volatile.Read(ref isExist))
                    return value;

                value = getAction();

                Volatile.Write(ref isExist, true);
            }

            return value;
        }
        set
        {
            lock (obj)
            {
                this.value = value;

                Volatile.Write(ref isExist, true);
            }
        }
    }

    public MyLazy(Func<T> getAction, bool canBeReseted)
            : this(getAction)
        => this.canBeReseted = canBeReseted;

    public MyLazy(Func<T> getAction)
        => this.getAction = getAction;

    public void Reset()
    {
        if (canBeReseted == false)
            return;

        lock (obj)
        {
            Volatile.Write(ref this.isExist, false);
        }
    }
}


Вопросы:

    1. действительно ли данный тип является потокобезопасным?
    2. может ли быть race condition который я пропустил?
Отредактировано 26.12.2018 12:37 RAza . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.