288 lines · 8.9 KB · C#
RawDownload
//******************************************************************************************************//  LogicalThreadLocal.cs - Gbtc////  Copyright © 2015, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  09/24/2015 - Stephen C. Wills//       Generated original version of source code.////****************************************************************************************************** using System;using System.Threading; namespace GSF.Threading{    /// <summary>    /// Represents a slot in the thread local memory space of each logical thread.    /// </summary>    public sealed class LogicalThreadLocal<T> : IDisposable    {        #region [ Members ]         // Nested Types        private class Slot        {            private T m_value;             public T Value            {                get                {                    return m_value;                }                set                {                    m_value = value;                }            }        }         // Events        private event EventHandler Disposed;         // Fields        private Func<T> m_newObjectFactory;        private ThreadLocal<T> m_threadLocal;         private int m_accessCount;        private int m_disposed;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="LogicalThreadLocal{T}"/> class.        /// </summary>        public LogicalThreadLocal()            : this(() => default(T))        {        }         /// <summary>        /// Creates a new instance of the <see cref="LogicalThreadLocal{T}"/> class.        /// </summary>        /// <param name="newObjectFactory">Factory to produce the initial value when accessing uninitialized values.</param>        public LogicalThreadLocal(Func<T> newObjectFactory)        {            m_newObjectFactory = newObjectFactory;            m_threadLocal = new ThreadLocal<T>(newObjectFactory);        }         /// <summary>        /// Releases the unmanaged resources before the <see cref="LogicalThreadLocal{T}"/> object is reclaimed by <see cref="GC"/>.        /// </summary>        ~LogicalThreadLocal()        {            Dispose(false);        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the thread local object        /// associated with the current logical thread.        /// </summary>        public T Value        {            get            {                Slot slot;                 return Access(() =>                {                    if (TryGetSlot(out slot))                        return slot.Value;                     if (!IsDisposed)                        return m_threadLocal.Value;                     return default(T);                });            }            set            {                Slot slot;                 Access(() =>                {                    if (TryGetSlot(out slot))                        slot.Value = value;                    else if (!IsDisposed)                        m_threadLocal.Value = value;                });            }        }         /// <summary>        /// Gets a flag that indicates whether this object has been disposed.        /// </summary>        private bool IsDisposed        {            get            {                return Interlocked.CompareExchange(ref m_disposed, 0, 0) != 0;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Releases all the resources used by the <see cref="LogicalThreadLocal{T}"/> object.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }         /// <summary>        /// Executes the given action in a protected code block that ensures all        /// unmanaged resources get cleaned up after a call to <see cref="Dispose"/>.        /// </summary>        /// <param name="action">The action to be executed.</param>        private void Access(Action action)        {            try            {                Interlocked.Increment(ref m_accessCount);                 if (IsDisposed)                    return;                 action();            }            finally            {                Interlocked.Decrement(ref m_accessCount);                 if (IsDisposed && Interlocked.CompareExchange(ref m_accessCount, 0, 0) == 0)                    OnDisposed(true);            }        }         /// <summary>        /// Executes the given function in a protected code block that ensures all        /// unmanaged resources get cleaned up after a call to <see cref="Dispose"/>.        /// </summary>        /// <param name="func">The function to be executed.</param>        private TResult Access<TResult>(Func<TResult> func)        {            try            {                Interlocked.Increment(ref m_accessCount);                return !IsDisposed ? func() : default(TResult);            }            finally            {                Interlocked.Decrement(ref m_accessCount);                 if (IsDisposed && Interlocked.CompareExchange(ref m_accessCount, 0, 0) == 0)                    OnDisposed(true);            }        }         /// <summary>        /// Attempts to get the instance of this slot from the current logical thread.        /// </summary>        /// <param name="slot">An instance of this slot.</param>        /// <returns>True if an instance of this slot is successfully retrieved from the current logical thread.</returns>        private bool TryGetSlot(out Slot slot)        {            LogicalThread currentThread;             if (IsDisposed)            {                slot = null;                return false;            }             currentThread = LogicalThread.CurrentThread;             if ((object)currentThread == null)            {                slot = null;                return false;            }             slot = currentThread.GetThreadLocal(this) as Slot;             if ((object)slot == null)            {                slot = new Slot();                slot.Value = m_newObjectFactory();                currentThread.SetThreadLocal(this, slot);                AttachToDisposed();            }             return true;        }         /// <summary>        /// Releases the unmanaged resources used by the <see cref="LogicalThreadLocal{T}"/> object and optionally releases the managed resources.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        private void Dispose(bool disposing)        {            Interlocked.CompareExchange(ref m_disposed, -1, 0);             if (Interlocked.CompareExchange(ref m_accessCount, 0, 0) == 0)                OnDisposed(disposing);        }         /// <summary>        /// Attaches logic to dispose of the slot in        /// the currently executing logical thread.        /// </summary>        private void AttachToDisposed()        {            WeakReference<LogicalThread> threadRef = new WeakReference<LogicalThread>(LogicalThread.CurrentThread);             Disposed += (sender, args) =>            {                LogicalThread thread;                 if (threadRef.TryGetTarget(out thread))                    thread.SetThreadLocal(this, null);            };        }         /// <summary>        /// Invokes the <see cref="Disposed"/> event handler.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        private void OnDisposed(bool disposing)        {            if (Interlocked.CompareExchange(ref m_disposed, 1, -1) == -1)            {                EventHandler disposed = Disposed;                 if ((object)disposed != null)                    disposed(this, EventArgs.Empty);                 if (disposing)                    m_threadLocal.Dispose();            }        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t