//****************************************************************************************************** // ManagedThreads.cs - Gbtc // // Copyright © 2012, 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://www.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: // ---------------------------------------------------------------------------------------------------- // 01/25/2008 - J. Ritchie Carroll // Initial version of source generated. // 09/11/2008 - J. Ritchie Carroll // Converted to C#. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace GSF.Threading { /// /// Maintains a reference to all managed threads /// public static class ManagedThreads { private static readonly LinkedList s_queuedThreads; private static readonly LinkedList s_activeThreads; static ManagedThreads() { s_queuedThreads = new LinkedList(); s_activeThreads = new LinkedList(); } /// /// Add an item to the active thread list /// /// /// Typically only used by standard threads when user calls "Start" /// internal static void Add(ManagedThread item) { // Standard threads are simply added to the active thread list when started lock (s_queuedThreads) { item.Status = ThreadStatus.Started; s_activeThreads.AddLast(item); } } /// /// Remove completed thread from active thread list /// internal static void Remove(ManagedThread item) { lock (s_queuedThreads) { s_activeThreads.Remove(item); } } /// /// Queue thread for processing /// /// /// Typically only used by queued threads to add work items to the queue /// internal static void Queue(ManagedThread item) { lock (s_queuedThreads) { s_queuedThreads.AddLast(item); } } /// /// Removes first item from the queue and transfers the item to the active thread list /// /// Next item to be processed internal static ManagedThread Pop() { ManagedThread item = null; // Transfer next queued thread to the active thread list lock (s_queuedThreads) { if (s_queuedThreads.Count > 0) { item = s_queuedThreads.First.Value; s_queuedThreads.RemoveFirst(); } if ((object)item != null) { // Capture current thread (this is owned by .NET ThreadPool) item.Thread = Thread.CurrentThread; item.Status = ThreadStatus.Started; s_activeThreads.AddLast(item); } } return item; } /// /// Returns a descriptive status of all queued and active mananged threads /// public static string ActiveThreadStatus { get { StringBuilder status = new StringBuilder(); ManagedThread[] items = QueuedThreads; int index = 0; // Managed Thread Count: 1 // // Thread 1 - Completed in 25 seconds // Type: Standard Thread // Name: GSF.Service.CalculatedMeasurementInitialization.Initialize() status.AppendFormat("Managed Thread Count: {0}{1}", items.Length, Environment.NewLine); status.AppendLine(); foreach (ManagedThread item in items) { index++; status.AppendFormat("Thread {0} - {1}{2}", index, ThreadStatusText(item), Environment.NewLine); status.AppendFormat(" Type: {0}{1}", Enum.GetName(typeof(ThreadType), item.Type), Environment.NewLine); status.AppendFormat(" Name: {0}{1}", item.Name, Environment.NewLine); status.AppendLine(); } return status.ToString(); } } private static string ThreadStatusText(ManagedThread item) { string runtime = item.RunTime.ToString(); switch (item.Status) { case ThreadStatus.Unstarted: return "Not Started"; case ThreadStatus.Queued: return "Queued"; case ThreadStatus.Executing: return "Executing for " + runtime; case ThreadStatus.Completed: return "Completed in " + runtime; case ThreadStatus.Aborted: return "Aborted, ran for " + runtime; default: return "Status Unknown"; } } /// /// Returns a copy of the currently queued and active threads /// public static ManagedThread[] QueuedThreads { get { List threads = new List(); lock (s_queuedThreads) { threads.AddRange(s_queuedThreads); threads.AddRange(s_activeThreads); } return threads.ToArray(); } } /// /// Removes a queued thread from thread pool if still queued, if allowAbort is True /// aborts the thread if executing (standard or queued) /// /// Thread to cancel /// Set to True to abort thread if executing /// An object that contains application-specific information, such as state, which can be used by the thread being aborted. public static void Cancel(ManagedThread item, bool allowAbort, object stateInfo) { if ((object)item == null) throw new ArgumentNullException("item"); LinkedListNode node; lock (s_queuedThreads) { // Change thread status to aborted item.Status = ThreadStatus.Aborted; // See if item is still queued for execution in thread pool node = s_queuedThreads.Find(item); // Handle abort or dequeue if ((object)node == null) { if (allowAbort) { // Started items may be aborted, even if running in thread pool if ((object)stateInfo == null) item.Thread.Abort(); else item.Thread.Abort(stateInfo); } } else { // Remove item from queue if queued thread has yet to start s_queuedThreads.Remove(node); } } } } }