private T NoneMode(HashSet <Thread> threads, Func <T> valueFactory) { if (Volatile.Read(ref _isValueCreated) != 0) { return(_valueFactory.Invoke()); } try { AddThread(threads); ValueForDebugDisplay = valueFactory(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); Volatile.Write(ref _isValueCreated, 1); return(ValueForDebugDisplay); } catch (Exception) { Volatile.Write(ref _isValueCreated, 0); throw; } finally { RemoveThread(threads); } }
private T CachingFullMode(Func <T> valueFactory, ManualResetEvent waitHandle, ref Thread thread) { if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { try { thread = Thread.CurrentThread; GC.KeepAlive(thread); _target = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(_target); return(_target); } catch (Exception exc) { _valueFactory = FuncHelper.GetThrowFunc <T>(exc); throw; } finally { waitHandle.Set(); thread = null; } } else { if (ReferenceEquals(thread, Thread.CurrentThread)) { throw new InvalidOperationException(); } waitHandle.WaitOne(); return(_valueFactory.Invoke()); } }
private T CachingFullMode(Func <T> valueFactory, EventWaitHandle waitHandle, ref Thread thread) { if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { try { thread = Thread.CurrentThread; GC.KeepAlive(thread); ValueForDebugDisplay = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); return(ValueForDebugDisplay); } catch (Exception exc) { _valueFactory = FuncHelper.GetThrowFunc <T>(exc); throw; } finally { waitHandle.Set(); thread = null; } } if (thread == Thread.CurrentThread) { throw new InvalidOperationException(); } waitHandle.WaitOne(); return(_valueFactory.Invoke()); }
private Lazy(Func <T> valueFactory, LazyThreadSafetyMode mode, bool cacheExceptions) { if (valueFactory == null) { throw new ArgumentNullException(nameof(valueFactory)); } switch (mode) { case LazyThreadSafetyMode.None: if (cacheExceptions) { var threads = new HashSet <Thread>(); _valueFactory = () => CachingNoneMode(threads, valueFactory); } else { var threads = new HashSet <Thread>(); _valueFactory = () => NoneMode(threads, valueFactory); } break; case LazyThreadSafetyMode.PublicationOnly: _valueFactory = PublicationOnlyMode; break; default: /*LazyThreadSafetyMode.ExecutionAndPublication*/ if (cacheExceptions) { Thread? thread = null; ManualResetEvent?manualResetEvent = null; _valueFactory = () => CachingFullMode(valueFactory, ref manualResetEvent, ref thread); } else { Thread? thread = null; ManualResetEvent?manualResetEvent = null; _valueFactory = () => FullMode(valueFactory, ref manualResetEvent, ref thread); } break; } T PublicationOnlyMode() { ValueForDebugDisplay = valueFactory(); if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); } return(ValueForDebugDisplay); } }
private T PublicationOnlyMode(Func <T> valueFactory) { _target = valueFactory(); if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { _valueFactory = FuncHelper.GetReturnFunc(_target); } return(_target); }
private T FullMode(Func <T> valueFactory, ref ManualResetEvent?waitHandle, ref Thread?thread) { if (waitHandle == null) { waitHandle = new ManualResetEvent(false); } while (Volatile.Read(ref _isValueCreated) != 1) { var foundThread = Interlocked.CompareExchange(ref thread, Thread.CurrentThread, null); if (foundThread == null) { try { ValueForDebugDisplay = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); Volatile.Write(ref _isValueCreated, 1); return(ValueForDebugDisplay); } finally { Volatile.Write(ref thread, default); waitHandle.Set(); if (Volatile.Read(ref _isValueCreated) == 1) { waitHandle.Close(); } } } if (foundThread == Thread.CurrentThread) { throw new InvalidOperationException(); } if (waitHandle.SafeWaitHandle.IsClosed) { continue; } try { waitHandle.WaitOne(); } catch (ObjectDisposedException exception) { _ = exception; } } return(_valueFactory.Invoke()); }
private T CachingFullMode(Func <T> valueFactory, ref ManualResetEvent?waitHandle, ref Thread?thread) { if (waitHandle == null) { waitHandle = new ManualResetEvent(false); } if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { Volatile.Write(ref thread, Thread.CurrentThread); try { ValueForDebugDisplay = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); return(ValueForDebugDisplay); } catch (Exception exc) { _valueFactory = FuncHelper.GetThrowFunc <T>(exc); throw; } finally { Volatile.Write(ref thread, null); waitHandle.Set(); waitHandle.Close(); } } if (Volatile.Read(ref thread) == Thread.CurrentThread) { throw new InvalidOperationException(); } if (waitHandle.SafeWaitHandle.IsClosed) { return(_valueFactory.Invoke()); } try { waitHandle.WaitOne(); } catch (ObjectDisposedException exception) { _ = exception; } return(_valueFactory.Invoke()); }
private T FullMode(Func <T> valueFactory, ManualResetEvent waitHandle, ref Thread thread, ref int preIsValueCreated) { back: if (Interlocked.CompareExchange(ref preIsValueCreated, 1, 0) == 0) { try { thread = Thread.CurrentThread; GC.KeepAlive(thread); _target = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(_target); Thread.VolatileWrite(ref _isValueCreated, 1); return(_target); } catch (Exception) { Thread.VolatileWrite(ref preIsValueCreated, 0); throw; } finally { waitHandle.Set(); thread = null; } } else { if (ReferenceEquals(thread, Thread.CurrentThread)) { throw new InvalidOperationException(); } else { waitHandle.WaitOne(); if (Thread.VolatileRead(ref _isValueCreated) == 1) { return(_valueFactory.Invoke()); } else { goto back; } } } }
private T NoneMode(Func <T> valueFactory, HashSet <Thread> threads) { // NOTICE this method has no null check var currentThread = Thread.CurrentThread; if (Thread.VolatileRead(ref _isValueCreated) == 0) { try { // lock (threads) // This is meant to not be thread-safe { if (threads.Contains(currentThread)) { throw new InvalidOperationException(); } else { threads.Add(currentThread); } } _target = valueFactory(); _valueFactory = FuncHelper.GetReturnFunc(_target); Thread.VolatileWrite(ref _isValueCreated, 1); return(_target); } catch (Exception) { Thread.VolatileWrite(ref _isValueCreated, 0); throw; } finally { // lock (threads) // This is meant to not be thread-safe { threads.Remove(Thread.CurrentThread); } } } else { return(_valueFactory.Invoke()); } }
private T FullMode(Func <T> valueFactory, EventWaitHandle waitHandle, ref Thread thread, ref int preIsValueCreated) { back: if (Interlocked.CompareExchange(ref preIsValueCreated, 1, 0) == 0) { try { thread = Thread.CurrentThread; GC.KeepAlive(thread); ValueForDebugDisplay = valueFactory.Invoke(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); Volatile.Write(ref _isValueCreated, 1); return(ValueForDebugDisplay); } catch (Exception) { Volatile.Write(ref preIsValueCreated, 0); throw; } finally { waitHandle.Set(); thread = null; } } if (thread == Thread.CurrentThread) { throw new InvalidOperationException(); } waitHandle.WaitOne(); if (Volatile.Read(ref _isValueCreated) == 1) { return(_valueFactory.Invoke()); } goto back; }
private Lazy(Func <T> valueFactory, LazyThreadSafetyMode mode, bool cacheExceptions) { if (valueFactory == null) { throw new ArgumentNullException(nameof(valueFactory)); } switch (mode) { case LazyThreadSafetyMode.None: { if (cacheExceptions) { var threads = new HashSet <Thread>(); _valueFactory = () => CachingNoneMode(threads); } else { var threads = new HashSet <Thread>(); _valueFactory = () => NoneMode(threads); } } break; case LazyThreadSafetyMode.PublicationOnly: { _valueFactory = PublicationOnlyMode; } break; default: /*LazyThreadSafetyMode.ExecutionAndPublication*/ { if (cacheExceptions) { Thread? thread = null; ManualResetEvent?manualResetEvent = null; _valueFactory = () => CachingFullMode(valueFactory, ref manualResetEvent, ref thread); } else { Thread? thread = null; ManualResetEvent?manualResetEvent = null; _valueFactory = () => FullMode(valueFactory, ref manualResetEvent, ref thread); } } break; } T CachingNoneMode(HashSet <Thread> threads) { if (Volatile.Read(ref _isValueCreated) != 0) { return(_valueFactory.Invoke()); } try { // lock (threads) // This is meant to not be thread-safe { var currentThread = Thread.CurrentThread; if (threads.Contains(currentThread)) { throw new InvalidOperationException(); } threads.Add(currentThread); } ValueForDebugDisplay = valueFactory(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); Volatile.Write(ref _isValueCreated, 1); return(ValueForDebugDisplay); } catch (Exception exception) { _valueFactory = FuncHelper.GetThrowFunc <T>(exception); throw; } finally { // lock (threads) // This is meant to not be thread-safe { threads.Remove(Thread.CurrentThread); } } } T NoneMode(HashSet <Thread> threads) { if (Volatile.Read(ref _isValueCreated) != 0) { return(_valueFactory.Invoke()); } try { // lock (threads) // This is meant to not be thread-safe { var currentThread = Thread.CurrentThread; if (threads.Contains(currentThread)) { throw new InvalidOperationException(); } threads.Add(currentThread); } ValueForDebugDisplay = valueFactory(); _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); Volatile.Write(ref _isValueCreated, 1); return(ValueForDebugDisplay); } catch (Exception) { Volatile.Write(ref _isValueCreated, 0); throw; } finally { // lock (threads) // This is meant to not be thread-safe { threads.Remove(Thread.CurrentThread); } } } T PublicationOnlyMode() { ValueForDebugDisplay = valueFactory(); if (Interlocked.CompareExchange(ref _isValueCreated, 1, 0) == 0) { _valueFactory = FuncHelper.GetReturnFunc(ValueForDebugDisplay); } return(ValueForDebugDisplay); } }