Donate. I desperately need donations to survive due to my health

Get paid by answering surveys Click here

Click here to donate

Remote/Work from Home jobs

Thread-safe implementation of lazy initialization which is exception-aware

I want to design a type similar to Lazy or in other words providing functionality similar to the following code snippet:

private T? value = default;

public T Value
{
    get
    {
        if (value.HasValue)
            return value.Value;

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

My goals are:

  1. Only one concurrent thread will attempt to create the underlying value. On successful creation, all waiting threads will receive the same value. If an unhandled exception occurs during creation, it will be re-thrown on each waiting thread, but it will not be cached and subsequent attempts to access the underlying value will re-try the creation and it may succeed.
  2. The type should be thread-safe.

Current version:

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);
        }
    }
}

Questions:

  1. Is this implementation is thread-safe?
  2. Could there be a race condition I missed?

Comments