├── .gitignore ├── Docs ├── Mono.jpg ├── Silverlight.jpg ├── SmartThreadPool.JPG ├── SmartThreadPool.html ├── WindowsCE.jpg ├── WindowsPhone.png └── WorkItemsGroup.JPG ├── LICENSE ├── README ├── STPExamples ├── CatchExceptionExample.cs ├── CooperativeCancelExample.cs ├── GetExceptionExample.cs ├── OnWIGIdleEventExample.cs ├── ParallelQuickSort.cs ├── PriorityExample.cs ├── STPExamples.csproj ├── SimpleExample.cs ├── SuspendedSTPStartExample.cs ├── SuspendedWIGStartExample.cs ├── ThreadEventsExample.cs ├── WaitForAllExample.cs ├── WaitForAnyExample.cs ├── WaitForIdleExample.cs └── WorkItemsGroupExample.cs ├── STPTests ├── PermutationGenerator.cs ├── QueueWorkItemHelper.cs ├── STPTests.csproj ├── TestActionT.cs ├── TestCancel.Abort.cs ├── TestCancel.cs ├── TestChainedDelegates.cs ├── TestConcurrencyChanges.cs ├── TestExceptions.cs ├── TestFalseFillStateWithParams.cs ├── TestFillStateWithParams.cs ├── TestFunc.cs ├── TestFuncT.cs ├── TestGetResult.cs ├── TestMaxQueueLength.cs ├── TestMultipleWorkItems.cs ├── TestParallelMethods.cs ├── TestPostExecute.cs ├── TestPriorityQueue.cs ├── TestQueueWorkItem.cs ├── TestStartSuspended.cs ├── TestStateDispose.cs ├── TestThreadApartmentState.cs ├── TestThreadIsBackground.cs ├── TestThreadPriority.cs ├── TestThreadsCreate.cs ├── TestWIGActionT.cs ├── TestWIGChainedDelegates.cs ├── TestWIGConcurrency.cs ├── TestWIGConcurrencyChanges.cs ├── TestWIGExceptions.cs ├── TestWIGFillStateWithParams.cs ├── TestWIGFuncT.cs ├── TestWIGGetResult.cs ├── TestWIGMultipleWorkItems.cs ├── TestWIGPostExecute.cs ├── TestWIGQueueWorkItem.cs ├── TestWIGStateDispose.cs ├── TestWIGWaitForIdle.cs ├── TestWaitForIdle.cs ├── TestWorkItemTimeout.cs ├── TestWorkItemsGroups.cs ├── TestWorkItemsQueue.cs └── packages.config ├── SmartThreadPool.sln ├── SmartThreadPool ├── CallerThreadContext.cs ├── CanceledWorkItemsGroup.cs ├── EventWaitHandleFactory.cs ├── Exceptions.cs ├── Interfaces.cs ├── InternalInterfaces.cs ├── PriorityQueue.cs ├── STPEventWaitHandle.cs ├── STPPerformanceCounter.cs ├── STPStartInfo.cs ├── SmartThreadPool.ThreadEntry.cs ├── SmartThreadPool.cs ├── SmartThreadPool.csproj ├── Stopwatch.cs ├── SynchronizedDictionary.cs ├── WIGStartInfo.cs ├── WorkItem.WorkItemResult.cs ├── WorkItem.cs ├── WorkItemFactory.cs ├── WorkItemInfo.cs ├── WorkItemResultTWrapper.cs ├── WorkItemsGroup.cs ├── WorkItemsGroupBase.cs └── WorkItemsQueue.cs ├── TestSmartThreadPool ├── App.ico ├── AssemblyInfo.cs ├── Form1.cs ├── Form1.resx ├── TestSmartThreadPool.csproj └── app.config ├── UsageControl ├── AssemblyInfo.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── QueueUsageControl.Designer.cs ├── QueueUsageControl.cs ├── QueueUsageControl.resx ├── QueueUsageEntry.cs ├── UsageControl.cs ├── UsageControl.csproj ├── UsageControl.resx ├── UsageHistoryControl.cs └── UsageHistoryControl.resx └── WorkItemsGroupDemo ├── Form1.Designer.cs ├── Form1.cs ├── Form1.resx ├── Program.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── WorkItemsGroupDemo.csproj └── app.config /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.log 21 | [Bb]in 22 | [Dd]ebug*/ 23 | *.lib 24 | *.sbr 25 | obj/ 26 | [Rr]elease*/ 27 | _ReSharper*/ 28 | [Tt]est[Rr]esult* 29 | publish/ 30 | SmartThreadPool/sign.proj 31 | packages/ 32 | .vs/ -------------------------------------------------------------------------------- /Docs/Mono.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/Mono.jpg -------------------------------------------------------------------------------- /Docs/Silverlight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/Silverlight.jpg -------------------------------------------------------------------------------- /Docs/SmartThreadPool.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/SmartThreadPool.JPG -------------------------------------------------------------------------------- /Docs/SmartThreadPool.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/SmartThreadPool.html -------------------------------------------------------------------------------- /Docs/WindowsCE.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/WindowsCE.jpg -------------------------------------------------------------------------------- /Docs/WindowsPhone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/WindowsPhone.png -------------------------------------------------------------------------------- /Docs/WorkItemsGroup.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/Docs/WorkItemsGroup.JPG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Microsoft Public License (MS-PL) 2 | 3 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 4 | 5 | 1. Definitions 6 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the 7 | same meaning here as under U.S. copyright law. 8 | A "contribution" is the original software, or any additions or changes to the software. 9 | A "contributor" is any person that distributes its contribution under this license. 10 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 11 | 12 | 2. Grant of Rights 13 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 14 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 15 | 16 | 3. Conditions and Limitations 17 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 18 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 19 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 20 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 21 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | SmartThreadPool project 2 | Links: 3 | http://www.codeproject.com/Articles/7933/Smart-Thread-Pool 4 | http://smartthreadpool.codeplex.com 5 | https://github.com/amibar/SmartThreadPool 6 | -------------------------------------------------------------------------------- /STPExamples/CatchExceptionExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Amib.Threading; 4 | 5 | namespace Examples 6 | { 7 | public class CatchExceptionExample 8 | { 9 | public void DoWork() 10 | { 11 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 12 | 13 | IWorkItemResult wir = smartThreadPool.QueueWorkItem(new Func(DoDiv), 10.0, 0.0); 14 | 15 | try 16 | { 17 | double result = wir.Result; 18 | } 19 | // Catch the exception that Result threw 20 | catch (WorkItemResultException e) 21 | { 22 | // Dump the inner exception which DoDiv threw 23 | Debug.WriteLine(e.InnerException); 24 | } 25 | 26 | smartThreadPool.Shutdown(); 27 | } 28 | 29 | private double DoDiv(double x, double y) 30 | { 31 | return x / y; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /STPExamples/CooperativeCancelExample.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class CooperativeCancelExample 7 | { 8 | public void DoWork(object state) 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | // Queue the work item 13 | IWorkItemResult wir = smartThreadPool.QueueWorkItem(DoRealWork); 14 | 15 | // Give the work item some time to complete. 16 | Thread.Sleep(1000); 17 | 18 | // If the work item hasn't completed yet then cancel it. 19 | if (!wir.IsCompleted) 20 | { 21 | wir.Cancel(); 22 | } 23 | 24 | smartThreadPool.Shutdown(); 25 | } 26 | 27 | // Do some lengthy work 28 | private void DoRealWork() 29 | { 30 | // Do something here. 31 | 32 | // Sample SmartThreadPool.IsWorkItemCanceled 33 | if (SmartThreadPool.IsWorkItemCanceled) 34 | { 35 | return; 36 | } 37 | 38 | // Sample the SmartThreadPool.IsWorkItemCanceled in a loop 39 | while (!SmartThreadPool.IsWorkItemCanceled) 40 | { 41 | // Do some real work here 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /STPExamples/GetExceptionExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class GetExceptionExample 7 | { 8 | private class DivArgs 9 | { 10 | public int x; 11 | public int y; 12 | } 13 | 14 | public void DoWork() 15 | { 16 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 17 | 18 | DivArgs divArgs = new DivArgs(); 19 | divArgs.x = 10; 20 | divArgs.y = 0; 21 | 22 | IWorkItemResult wir = 23 | smartThreadPool.QueueWorkItem(new 24 | WorkItemCallback(this.DoDiv), divArgs); 25 | 26 | Exception e; 27 | object obj = wir.GetResult(out e); 28 | // e contains the expetion that DoDiv threw 29 | if(null == e) 30 | { 31 | int result = (int)obj; 32 | } 33 | else 34 | { 35 | // Do something with the exception 36 | } 37 | 38 | smartThreadPool.Shutdown(); 39 | } 40 | 41 | private object DoDiv(object state) 42 | { 43 | DivArgs divArgs = (DivArgs)state; 44 | return (divArgs.x / divArgs.y); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /STPExamples/OnWIGIdleEventExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Amib.Threading; 4 | 5 | namespace Examples 6 | { 7 | public class OnWIGIdleEventExample 8 | { 9 | public void DoWork(object [] states) 10 | { 11 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 12 | 13 | IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1); 14 | 15 | wig.OnIdle += wig_OnIdle; 16 | 17 | foreach(object state in states) 18 | { 19 | wig.QueueWorkItem(new 20 | WorkItemCallback(this.DoSomeWork), state); 21 | } 22 | 23 | smartThreadPool.WaitForIdle(); 24 | smartThreadPool.Shutdown(); 25 | } 26 | 27 | private object DoSomeWork(object state) 28 | { 29 | // Do the work 30 | return null; 31 | } 32 | 33 | private void wig_OnIdle(IWorkItemsGroup workItemsGroup) 34 | { 35 | Debug.WriteLine("WIG is idle"); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /STPExamples/ParallelQuickSort.cs: -------------------------------------------------------------------------------- 1 | using Amib.Threading; 2 | 3 | namespace STPExamples 4 | { 5 | /// 6 | /// This is a Parallel QuickSort example. 7 | /// It shows how to use the QueueWorkItem with Action methods. 8 | /// 9 | public class ParallelQuickSort 10 | { 11 | public static void Main() 12 | { 13 | // Generate an array 14 | int[] array = GenerateArray(100); 15 | 16 | // Create a Smart Thread Pool 17 | SmartThreadPool stp = new SmartThreadPool(); 18 | 19 | // Use the Smart Thread Pool to parallel the sort 20 | QuickSort(stp, array); 21 | } 22 | 23 | /// 24 | /// QuickSort array using wig to parallel the sort 25 | /// 26 | /// A IWorkItemsGroup to use to parallel the sort 27 | /// The array of items to sort 28 | public static void QuickSort(IWorkItemsGroup wig, int[] array) 29 | { 30 | // Initiate the QuickSort 31 | wig.QueueWorkItem(QuickSort, wig, array, 0, array.Length - 1); 32 | 33 | // Wait for the sort to complete. 34 | wig.WaitForIdle(); 35 | } 36 | 37 | /// 38 | /// Sort a subarray in array, starting with the left item and ending in the right item. 39 | /// The method uses the IWorkItemsGroup wig to parallel the sort. 40 | /// 41 | /// A IWorkItemsGroup to use to parallel the sort 42 | /// The array of items to sort 43 | /// The left index in the subarray 44 | /// The right index in the subarray 45 | private static void QuickSort(IWorkItemsGroup wig, int[] array, int left, int right) 46 | { 47 | if (right > left) 48 | { 49 | int pivotIndex = left; 50 | int pivotNewIndex = Partition(array, left, right, pivotIndex); 51 | 52 | wig.QueueWorkItem(QuickSort, wig, array, left, pivotNewIndex - 1); 53 | wig.QueueWorkItem(QuickSort, wig, array, pivotNewIndex + 1, right); 54 | } 55 | } 56 | 57 | /// 58 | /// Partition a subarray of array 59 | /// (This is part of the QuickSort algorithm) 60 | /// 61 | /// 62 | private static int Partition(int[] array, int left, int right, int pivotIndex) 63 | { 64 | int pivotValue = array[pivotIndex]; 65 | Swap(array, pivotIndex, right); 66 | int storeIndex = left; 67 | 68 | for (int i = left; i < right; i++) 69 | { 70 | if (array[i] <= pivotValue) 71 | { 72 | Swap(array, i, storeIndex); 73 | ++storeIndex; 74 | } 75 | } 76 | Swap(array, storeIndex, right); 77 | return storeIndex; 78 | } 79 | 80 | /// 81 | /// Swap between two item in the array 82 | /// 83 | /// Array of integers 84 | /// First index 85 | /// Second index 86 | private static void Swap(int[] array, int index1, int index2) 87 | { 88 | int temp = array[index1]; 89 | array[index1] = array[index2]; 90 | array[index2] = temp; 91 | } 92 | 93 | /// 94 | /// Generate an array with the numbers 0-count ordered in reverse 95 | /// 96 | /// The number of items in the array 97 | /// Returns the generated array 98 | private static int[] GenerateArray(int count) 99 | { 100 | int[] array = new int[count]; 101 | for (int i = 0; i < array.Length; i++) 102 | { 103 | array[i] = array.Length - i; 104 | } 105 | return array; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /STPExamples/PriorityExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Amib.Threading; 4 | 5 | namespace Examples 6 | { 7 | public class PriorityExample 8 | { 9 | public void DoWork() 10 | { 11 | STPStartInfo stpStartInfo = new STPStartInfo(); 12 | stpStartInfo.StartSuspended = true; 13 | 14 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 15 | 16 | smartThreadPool.QueueWorkItem( 17 | new WorkItemCallback(this.DoSomeWork), 18 | "Queued first", 19 | WorkItemPriority.BelowNormal); 20 | 21 | smartThreadPool.QueueWorkItem( 22 | new WorkItemCallback(this.DoSomeWork), 23 | "Queued second", 24 | WorkItemPriority.AboveNormal); 25 | 26 | smartThreadPool.Start(); 27 | 28 | smartThreadPool.WaitForIdle(); 29 | 30 | smartThreadPool.Shutdown(); 31 | } 32 | 33 | private object DoSomeWork(object state) 34 | { 35 | Debug.WriteLine(state); 36 | return null; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /STPExamples/STPExamples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net46;netcoreapp2.0 5 | STPExamples 6 | STPExamples 7 | TRACE; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /STPExamples/SimpleExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class SimpleExample 7 | { 8 | public void DoWork(int[] numbers) 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | // Queue the work item 13 | IWorkItemResult wir = smartThreadPool.QueueWorkItem(new Func(CalcAverage), numbers); 14 | 15 | // Do some other work here 16 | 17 | // Get the result of the operation 18 | double average = wir.Result; 19 | 20 | smartThreadPool.Shutdown(); 21 | } 22 | 23 | // Do the real work 24 | private double CalcAverage(int[] numbers) 25 | { 26 | double average = 0.0; 27 | 28 | // Do the real work here and put 29 | // the result in 'result' 30 | 31 | return average; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /STPExamples/SuspendedSTPStartExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class SuspendedSTPStartExample 7 | { 8 | public void DoWork(object [] states) 9 | { 10 | STPStartInfo stpStartInfo = new STPStartInfo(); 11 | stpStartInfo.StartSuspended = true; 12 | 13 | SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo); 14 | 15 | foreach(object state in states) 16 | { 17 | smartThreadPool.QueueWorkItem(new 18 | WorkItemCallback(this.DoSomeWork), state); 19 | } 20 | 21 | // Start working on the work items in the queue 22 | smartThreadPool.Start(); 23 | 24 | // Wait for the completion of all work items 25 | smartThreadPool.WaitForIdle(); 26 | 27 | smartThreadPool.Shutdown(); 28 | } 29 | 30 | private object DoSomeWork(object state) 31 | { 32 | // Do the work 33 | return null; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /STPExamples/SuspendedWIGStartExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class SuspendedWIGStartExample 7 | { 8 | public void DoWork(object [] states) 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 13 | wigStartInfo.StartSuspended = true; 14 | 15 | IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1, wigStartInfo); 16 | 17 | foreach(object state in states) 18 | { 19 | wig.QueueWorkItem(new 20 | WorkItemCallback(this.DoSomeWork), state); 21 | } 22 | 23 | // Start working on the work items in the work items group queue 24 | wig.Start(); 25 | 26 | // Wait for the completion of all work items 27 | wig.WaitForIdle(); 28 | 29 | smartThreadPool.Shutdown(); 30 | } 31 | 32 | private object DoSomeWork(object state) 33 | { 34 | // Do the work 35 | return null; 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /STPExamples/ThreadEventsExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace STPExamples 5 | { 6 | public class MyResource : IDisposable 7 | { 8 | // ... 9 | 10 | public void DoIt() 11 | { 12 | //... 13 | } 14 | 15 | public void Dispose() 16 | { 17 | //... 18 | } 19 | } 20 | 21 | public class ThreadEventsExample 22 | { 23 | public static void Main() 24 | { 25 | 26 | SmartThreadPool stp = new SmartThreadPool(); 27 | stp.OnThreadInitialization += OnInitialization; 28 | stp.OnThreadTermination += OnTermination; 29 | 30 | stp.QueueWorkItem(DoSomeWork); 31 | } 32 | 33 | [ThreadStatic] 34 | private static MyResource _resource; 35 | 36 | public static void OnInitialization() 37 | { 38 | // Initialize the resource 39 | _resource = new MyResource(); 40 | } 41 | 42 | private static object DoSomeWork(object state) 43 | { 44 | // Use the resouce 45 | _resource.DoIt(); 46 | 47 | return null; 48 | } 49 | 50 | public static void OnTermination() 51 | { 52 | // Do resource cleanup 53 | _resource.Dispose(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /STPExamples/WaitForAllExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class WaitForAllExample 7 | { 8 | public void DoWork() 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | IWorkItemResult wir1 = 13 | smartThreadPool.QueueWorkItem(new 14 | WorkItemCallback(this.DoSomeWork1), null); 15 | 16 | IWorkItemResult wir2 = 17 | smartThreadPool.QueueWorkItem(new 18 | WorkItemCallback(this.DoSomeWork2), null); 19 | 20 | bool success = SmartThreadPool.WaitAll(new IWorkItemResult [] { wir1, wir2 }); 21 | 22 | if (success) 23 | { 24 | int result1 = (int)wir1.Result; 25 | int result2 = (int)wir2.Result; 26 | } 27 | 28 | smartThreadPool.Shutdown(); 29 | } 30 | 31 | private object DoSomeWork1(object state) 32 | { 33 | return 1; 34 | } 35 | 36 | private object DoSomeWork2(object state) 37 | { 38 | return 2; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /STPExamples/WaitForAnyExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using Amib.Threading; 5 | 6 | namespace Examples 7 | { 8 | public class WaitForAnyExample 9 | { 10 | public void DoWork() 11 | { 12 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 13 | 14 | IWorkItemResult wir1 = 15 | smartThreadPool.QueueWorkItem(new 16 | WorkItemCallback(this.DoSomeWork1), null); 17 | 18 | IWorkItemResult wir2 = 19 | smartThreadPool.QueueWorkItem(new 20 | WorkItemCallback(this.DoSomeWork2), null); 21 | 22 | IWorkItemResult [] wirs = new IWorkItemResult [] { wir1, wir2 }; 23 | 24 | int index = SmartThreadPool.WaitAny(wirs); 25 | 26 | if (index != WaitHandle.WaitTimeout) 27 | { 28 | int result = (int)wirs[index].Result; 29 | } 30 | 31 | smartThreadPool.Shutdown(); 32 | } 33 | 34 | private object DoSomeWork1(object state) 35 | { 36 | return 1; 37 | } 38 | 39 | private object DoSomeWork2(object state) 40 | { 41 | return 1; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /STPExamples/WaitForIdleExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class WaitForIdleExample 7 | { 8 | public void DoWork(object [] states) 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | foreach(object state in states) 13 | { 14 | smartThreadPool.QueueWorkItem(new 15 | WorkItemCallback(this.DoSomeWork), state); 16 | } 17 | 18 | // Wait for the completion of all work items 19 | smartThreadPool.WaitForIdle(); 20 | 21 | smartThreadPool.Shutdown(); 22 | } 23 | 24 | private object DoSomeWork(object state) 25 | { 26 | // Do the work 27 | return null; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /STPExamples/WorkItemsGroupExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | 4 | namespace Examples 5 | { 6 | public class WorkItemsGroupExample 7 | { 8 | public void DoWork(object [] states) 9 | { 10 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 11 | 12 | // Create a work items group that processes 13 | // one work item at a time 14 | IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1); 15 | 16 | // Queue some work items 17 | foreach(object state in states) 18 | { 19 | wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), state); 20 | } 21 | 22 | // Wait for the completion of all work items in the work items group 23 | wig.WaitForIdle(); 24 | 25 | smartThreadPool.Shutdown(); 26 | } 27 | 28 | private object DoSomeWork(object state) 29 | { 30 | // Do the work 31 | return null; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /STPTests/PermutationGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | /* 5 | * The code below generates permutations. 6 | * 7 | * The original code was written by Michael Gilleland, 8 | * and can be found in the following site 9 | * http://www.merriampark.com/perm.htm 10 | * 11 | * I translated it to C# from Java. 12 | */ 13 | namespace SmartThreadPoolTests 14 | { 15 | //-------------------------------------- 16 | // Systematically generate permutations. 17 | //-------------------------------------- 18 | 19 | public class PermutationGenerator : IEnumerable 20 | { 21 | private object [] _objects; 22 | 23 | public PermutationGenerator(object [] objects) 24 | { 25 | _objects = (object [])objects.Clone(); 26 | } 27 | 28 | #region IEnumerable Members 29 | 30 | public IEnumerator GetEnumerator() 31 | { 32 | return new PermutationGeneratorEnumerator(_objects); 33 | } 34 | 35 | #endregion 36 | 37 | private class PermutationGeneratorEnumerator : IEnumerator 38 | { 39 | private object [] _objects; 40 | private object [] _currentPermutation; 41 | private PermutationGeneratorHelper _permutationGeneratorHelper; 42 | 43 | public PermutationGeneratorEnumerator(object [] objects) 44 | { 45 | _objects = objects; 46 | Reset(); 47 | } 48 | 49 | #region IEnumerator Members 50 | 51 | public void Reset() 52 | { 53 | _permutationGeneratorHelper = new PermutationGeneratorHelper(_objects.Length); 54 | } 55 | 56 | public object Current 57 | { 58 | get 59 | { 60 | return _currentPermutation; 61 | } 62 | } 63 | 64 | public bool MoveNext() 65 | { 66 | if (_permutationGeneratorHelper.hasMore()) 67 | { 68 | _currentPermutation = new object[_objects.Length]; 69 | int [] indices = _permutationGeneratorHelper.getNext(); 70 | for (int i = 0; i < indices.Length; i++) 71 | { 72 | _currentPermutation[i] = _objects[indices[i]]; 73 | } 74 | return true; 75 | } 76 | _currentPermutation = null; 77 | return false; 78 | } 79 | 80 | #endregion 81 | } 82 | 83 | 84 | private class PermutationGeneratorHelper 85 | { 86 | 87 | private int[] a; 88 | private long numLeft; 89 | private long total; 90 | 91 | //----------------------------------------------------------- 92 | // Constructor. WARNING: Don't make n too large. 93 | // Recall that the number of permutations is n! 94 | // which can be very large, even when n is as small as 20 -- 95 | // 20! = 2,432,902,008,176,640,000 and 96 | // 21! is too big to fit into a Java long, which is 97 | // why we use long instead. 98 | //---------------------------------------------------------- 99 | 100 | public PermutationGeneratorHelper (int n) 101 | { 102 | if (n < 1) 103 | { 104 | throw new ArgumentOutOfRangeException("n", n, "Min 1"); 105 | } 106 | a = new int[n]; 107 | total = getFactorial (n); 108 | reset(); 109 | } 110 | 111 | //------ 112 | // Reset 113 | //------ 114 | 115 | public void reset () 116 | { 117 | for (int i = 0; i < a.Length; i++) 118 | { 119 | a[i] = i; 120 | } 121 | numLeft = total; 122 | } 123 | 124 | //------------------------------------------------ 125 | // Return number of permutations not yet generated 126 | //------------------------------------------------ 127 | 128 | public long getNumLeft () 129 | { 130 | return numLeft; 131 | } 132 | 133 | //------------------------------------ 134 | // Return total number of permutations 135 | //------------------------------------ 136 | 137 | public long getTotal () 138 | { 139 | return total; 140 | } 141 | 142 | //----------------------------- 143 | // Are there more permutations? 144 | //----------------------------- 145 | 146 | public bool hasMore () 147 | { 148 | return (numLeft > 0); 149 | } 150 | 151 | //------------------ 152 | // Compute factorial 153 | //------------------ 154 | 155 | private static long getFactorial (int n) 156 | { 157 | long fact = 1; 158 | for (int i = n; i > 1; i--) 159 | { 160 | fact = fact * i; 161 | } 162 | return fact; 163 | } 164 | 165 | //-------------------------------------------------------- 166 | // Generate next permutation (algorithm from Rosen p. 284) 167 | //-------------------------------------------------------- 168 | 169 | public int[] getNext () 170 | { 171 | 172 | if (numLeft == total) 173 | { 174 | --numLeft; 175 | return a; 176 | } 177 | 178 | int temp; 179 | 180 | // Find largest index j with a[j] < a[j+1] 181 | 182 | int j = a.Length - 2; 183 | while (a[j] > a[j+1]) 184 | { 185 | j--; 186 | } 187 | 188 | // Find index k such that a[k] is smallest integer 189 | // greater than a[j] to the right of a[j] 190 | 191 | int k = a.Length - 1; 192 | while (a[j] > a[k]) 193 | { 194 | k--; 195 | } 196 | 197 | // Interchange a[j] and a[k] 198 | 199 | temp = a[k]; 200 | a[k] = a[j]; 201 | a[j] = temp; 202 | 203 | // Put tail end of permutation after jth position in increasing order 204 | 205 | int r = a.Length - 1; 206 | int s = j + 1; 207 | 208 | while (r > s) 209 | { 210 | temp = a[s]; 211 | a[s] = a[r]; 212 | a[r] = temp; 213 | r--; 214 | s++; 215 | } 216 | 217 | --numLeft; 218 | return a; 219 | } 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /STPTests/STPTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net46;netcoreapp3.1;net5.0 5 | STPTests 6 | STPTests 7 | TRACE; 8 | Debug;Release;Publish 9 | 10 | 11 | 12 | true 13 | 14 | 15 | 16 | true 17 | ..\publish\Keys\STP.snk 18 | 19 | 20 | 21 | true 22 | 23 | 24 | 25 | true 26 | ..\publish\Keys\STP.snk 27 | 28 | 29 | 30 | true 31 | 32 | 33 | 34 | true 35 | ..\publish\Keys\STP.snk 36 | 37 | 38 | 39 | 40 | 41 | 42 | all 43 | runtime; build; native; contentfiles; analyzers; buildtransitive 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /STPTests/TestActionT.cs: -------------------------------------------------------------------------------- 1 | using Amib.Threading; 2 | using NUnit.Framework; 3 | 4 | namespace SmartThreadPoolTests 5 | { 6 | /// 7 | /// Summary description for TestCancel. 8 | /// 9 | [TestFixture] 10 | [Category("TestActionT")] 11 | public class TestActionT 12 | { 13 | private SmartThreadPool _stp; 14 | private object _result; 15 | 16 | [SetUp] 17 | public void Init() 18 | { 19 | _stp = new SmartThreadPool(); 20 | } 21 | 22 | [TearDown] 23 | public void Fini() 24 | { 25 | _stp.Shutdown(); 26 | } 27 | 28 | [Test] 29 | public void ActionT0() 30 | { 31 | _result = null; 32 | 33 | IWorkItemResult wir = _stp.QueueWorkItem(MaxInt); 34 | 35 | wir.GetResult(); 36 | 37 | Assert.AreEqual(_result, int.MaxValue); 38 | } 39 | 40 | [Test] 41 | public void ActionT1() 42 | { 43 | _result = null; 44 | 45 | IWorkItemResult wir = _stp.QueueWorkItem(Not, true); 46 | 47 | wir.GetResult(); 48 | 49 | Assert.AreEqual(_result, false); 50 | } 51 | 52 | [Test] 53 | public void ActionT2() 54 | { 55 | _result = null; 56 | 57 | IWorkItemResult wir = _stp.QueueWorkItem(Concat, "ABC", "xyz"); 58 | 59 | wir.GetResult(); 60 | 61 | Assert.AreEqual(_result, "ABCxyz"); 62 | } 63 | 64 | [Test] 65 | public void ActionT3() 66 | { 67 | _result = null; 68 | 69 | IWorkItemResult wir = _stp.QueueWorkItem(Substring, "ABCDEF", 1, 2); 70 | 71 | wir.GetResult(); 72 | 73 | Assert.AreEqual(_result, "BC"); 74 | } 75 | 76 | [Test] 77 | public void ActionT4() 78 | { 79 | _result = null; 80 | 81 | int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 82 | 83 | IWorkItemResult wir = _stp.QueueWorkItem(Subarray, numbers, 1, 2, 3); 84 | 85 | wir.GetResult(); 86 | 87 | Assert.AreEqual(_result, new int[] { 2, 3, 2, 3, 2, 3, }); 88 | } 89 | 90 | private void MaxInt() 91 | { 92 | _result = int.MaxValue; 93 | } 94 | 95 | private void Not(bool flag) 96 | { 97 | _result = !flag; 98 | } 99 | 100 | private void Concat(string s1, string s2) 101 | { 102 | _result = s1 + s2; 103 | } 104 | 105 | private void Substring(string s, int startIndex, int length) 106 | { 107 | _result = s.Substring(startIndex, length); 108 | } 109 | 110 | private void Subarray(int[] numbers, int startIndex, int length, int repeat) 111 | { 112 | int[] result = new int[length * repeat]; 113 | for (int i = 0; i < repeat; i++) 114 | { 115 | for (int j = 0; j < length; j++) 116 | { 117 | result[i * length + j] = numbers[startIndex + j]; 118 | } 119 | } 120 | 121 | _result = result; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /STPTests/TestChainedDelegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | using Amib.Threading; 5 | 6 | namespace SmartThreadPoolTests 7 | { 8 | /// 9 | /// Summary description for TestChainedDelegates. 10 | /// 11 | [TestFixture] 12 | [Category("TestChainedDelegates")] 13 | public class TestChainedDelegates 14 | { 15 | [Test] 16 | public void GoodCallback() 17 | { 18 | SmartThreadPool stp = new SmartThreadPool(); 19 | 20 | stp.QueueWorkItem(new WorkItemCallback(DoWork)); 21 | 22 | stp.WaitForIdle(); 23 | 24 | stp.Shutdown(); 25 | } 26 | 27 | [Test] 28 | public void ChainedDelegatesCallback() 29 | { 30 | Assert.Throws(() => 31 | { 32 | 33 | SmartThreadPool stp = new SmartThreadPool(); 34 | 35 | WorkItemCallback workItemCallback = new WorkItemCallback(DoWork); 36 | workItemCallback += new WorkItemCallback(DoWork); 37 | 38 | stp.QueueWorkItem(workItemCallback); 39 | 40 | stp.WaitForIdle(); 41 | 42 | stp.Shutdown(); 43 | }); 44 | } 45 | 46 | [Test] 47 | public void GoodPostExecute() 48 | { 49 | SmartThreadPool stp = new SmartThreadPool(); 50 | 51 | stp.QueueWorkItem( 52 | new WorkItemCallback(DoWork), 53 | null, 54 | new PostExecuteWorkItemCallback(DoPostExecute)); 55 | 56 | stp.WaitForIdle(); 57 | 58 | stp.Shutdown(); 59 | } 60 | 61 | [Test] 62 | public void ChainedDelegatesPostExecute() 63 | { 64 | Assert.Throws(() => 65 | { 66 | 67 | SmartThreadPool stp = new SmartThreadPool(); 68 | 69 | PostExecuteWorkItemCallback postExecuteWorkItemCallback = DoPostExecute; 70 | postExecuteWorkItemCallback += DoPostExecute; 71 | 72 | stp.QueueWorkItem( 73 | new WorkItemCallback(DoWork), 74 | null, 75 | postExecuteWorkItemCallback); 76 | 77 | stp.WaitForIdle(); 78 | 79 | stp.Shutdown(); 80 | }); 81 | } 82 | 83 | 84 | private object DoWork(object state) 85 | { 86 | return null; 87 | } 88 | 89 | private void DoPostExecute(IWorkItemResult wir) 90 | { 91 | } 92 | 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /STPTests/TestConcurrencyChanges.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Diagnostics; 4 | 5 | using NUnit.Framework; 6 | 7 | using Amib.Threading; 8 | 9 | namespace SmartThreadPoolTests 10 | { 11 | /// 12 | /// Summary description for TestConcurrencyChanges. 13 | /// 14 | [TestFixture] 15 | [Category("TestConcurrencyChanges")] 16 | public class TestConcurrencyChanges 17 | { 18 | /// 19 | /// Example of waiting for idle 20 | /// 21 | [Test] 22 | public void TestMaxThreadsChange() 23 | { 24 | SmartThreadPool smartThreadPool = new SmartThreadPool(1 * 1000, 1, 0); 25 | 26 | for (int i = 0; i < 100; ++i) 27 | { 28 | smartThreadPool.QueueWorkItem( 29 | new WorkItemCallback(this.DoSomeWork), 30 | null); 31 | } 32 | 33 | bool success = WaitForMaxThreadsValue(smartThreadPool, 1, 1 * 1000); 34 | Assert.IsTrue(success); 35 | 36 | smartThreadPool.MaxThreads = 5; 37 | success = WaitForMaxThreadsValue(smartThreadPool, 5, 2 * 1000); 38 | Assert.IsTrue(success); 39 | 40 | smartThreadPool.MaxThreads = 25; 41 | success = WaitForMaxThreadsValue(smartThreadPool, 25, 4 * 1000); 42 | Assert.IsTrue(success); 43 | 44 | smartThreadPool.MaxThreads = 10; 45 | success = WaitForMaxThreadsValue(smartThreadPool, 10, 10 * 1000); 46 | Assert.IsTrue(success); 47 | 48 | smartThreadPool.Shutdown(); 49 | } 50 | 51 | [Test] 52 | public void TestMinThreadsChange() 53 | { 54 | SmartThreadPool smartThreadPool = new SmartThreadPool(1 * 1000, 25, 0); 55 | 56 | 57 | 58 | bool success = WaitForMinThreadsValue(smartThreadPool, 0, 1 * 1000); 59 | Assert.IsTrue(success); 60 | 61 | smartThreadPool.MinThreads = 5; 62 | success = WaitForMinThreadsValue(smartThreadPool, 5, 2 * 1000); 63 | Assert.IsTrue(success); 64 | 65 | smartThreadPool.MinThreads = 25; 66 | success = WaitForMinThreadsValue(smartThreadPool, 25, 4 * 1000); 67 | Assert.IsTrue(success); 68 | 69 | smartThreadPool.MinThreads = 10; 70 | success = WaitForMinThreadsValue(smartThreadPool, 10, 10 * 1000); 71 | Assert.IsTrue(success); 72 | 73 | smartThreadPool.Shutdown(); 74 | } 75 | 76 | /// 77 | /// Example of waiting for idle 78 | /// 79 | [Test] 80 | public void TestConcurrencyChange() 81 | { 82 | SmartThreadPool smartThreadPool = new SmartThreadPool(10 * 1000, 1, 0); 83 | 84 | bool success = false; 85 | 86 | for (int i = 0; i < 100; ++i) 87 | { 88 | smartThreadPool.QueueWorkItem( 89 | new WorkItemCallback(this.DoSomeWork), 90 | null); 91 | } 92 | 93 | smartThreadPool.Concurrency = 1; 94 | success = WaitForMaxThreadsValue(smartThreadPool, 1, 1 * 1000); 95 | Assert.IsTrue(success); 96 | 97 | smartThreadPool.Concurrency = 5; 98 | success = WaitForMaxThreadsValue(smartThreadPool, 5, 2 * 1000); 99 | Assert.IsTrue(success); 100 | 101 | smartThreadPool.Concurrency = 25; 102 | success = WaitForMaxThreadsValue(smartThreadPool, 25, 4 * 1000); 103 | Assert.IsTrue(success); 104 | 105 | smartThreadPool.Concurrency = 10; 106 | success = WaitForMaxThreadsValue(smartThreadPool, 10, 10 * 1000); 107 | Assert.IsTrue(success); 108 | 109 | smartThreadPool.Shutdown(); 110 | } 111 | 112 | 113 | private bool WaitForMaxThreadsValue(SmartThreadPool smartThreadPool, int maxThreadsCount, int timeout) 114 | { 115 | DateTime end = DateTime.Now + new TimeSpan(0, 0, 0, 0, timeout); 116 | 117 | bool success = false; 118 | while(DateTime.Now <= end && !success) 119 | { 120 | success = (smartThreadPool.InUseThreads == maxThreadsCount); 121 | Thread.Sleep(10); 122 | } 123 | 124 | return success; 125 | } 126 | 127 | private bool WaitForMinThreadsValue(SmartThreadPool smartThreadPool, int minThreadsCount, int timeout) 128 | { 129 | DateTime end = DateTime.Now + new TimeSpan(0, 0, 0, 0, timeout); 130 | 131 | bool success = false; 132 | while (DateTime.Now <= end && !success) 133 | { 134 | success = (smartThreadPool.ActiveThreads == minThreadsCount); 135 | Thread.Sleep(10); 136 | } 137 | 138 | return success; 139 | } 140 | 141 | 142 | private int x = 0; 143 | private object DoSomeWork(object state) 144 | { 145 | Debug.WriteLine(Interlocked.Increment(ref x)); 146 | Thread.Sleep(1000); 147 | return 1; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /STPTests/TestExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | using NUnit.Framework; 4 | 5 | namespace SmartThreadPoolTests 6 | { 7 | /// 8 | /// Summary description for TestExceptions. 9 | /// 10 | [TestFixture] 11 | [Category("TestExceptions")] 12 | public class TestExceptions 13 | { 14 | private class DivArgs 15 | { 16 | public int x; 17 | public int y; 18 | } 19 | 20 | [Test] 21 | public void ExceptionThrowing() 22 | { 23 | SmartThreadPool _smartThreadPool = new SmartThreadPool(); 24 | 25 | DivArgs divArgs = new DivArgs(); 26 | divArgs.x = 10; 27 | divArgs.y = 0; 28 | 29 | IWorkItemResult wir = 30 | _smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs); 31 | 32 | try 33 | { 34 | wir.GetResult(); 35 | } 36 | catch(WorkItemResultException wire) 37 | { 38 | Assert.IsTrue(wire.InnerException is DivideByZeroException); 39 | return; 40 | } 41 | catch(Exception e) 42 | { 43 | e.GetHashCode(); 44 | Assert.Fail(); 45 | } 46 | Assert.Fail(); 47 | } 48 | 49 | [Test] 50 | public void ExceptionReturning() 51 | { 52 | bool success = true; 53 | 54 | SmartThreadPool _smartThreadPool = new SmartThreadPool(); 55 | 56 | DivArgs divArgs = new DivArgs(); 57 | divArgs.x = 10; 58 | divArgs.y = 0; 59 | 60 | IWorkItemResult wir = 61 | _smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs); 62 | 63 | Exception e = null; 64 | try 65 | { 66 | wir.GetResult(out e); 67 | } 68 | catch (Exception ex) 69 | { 70 | ex.GetHashCode(); 71 | success = false; 72 | } 73 | 74 | Assert.IsTrue(success); 75 | Assert.IsTrue(e is DivideByZeroException); 76 | } 77 | 78 | private object DoDiv(object state) 79 | { 80 | DivArgs divArgs = (DivArgs)state; 81 | return (divArgs.x / divArgs.y); 82 | } 83 | 84 | [Test] 85 | public void ExceptionType() 86 | { 87 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 88 | 89 | var workItemResult = smartThreadPool.QueueWorkItem(new Func(ExceptionMethod)); 90 | 91 | smartThreadPool.WaitForIdle(); 92 | 93 | Assert.IsInstanceOf(workItemResult.Exception); 94 | 95 | smartThreadPool.Shutdown(); 96 | } 97 | 98 | public int ExceptionMethod() 99 | { 100 | throw new NotImplementedException(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /STPTests/TestFunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | using Amib.Threading; 6 | using NUnit.Framework; 7 | 8 | namespace STPTests 9 | { 10 | /// 11 | /// Summary description for TestCancel. 12 | /// 13 | [TestFixture] 14 | [Category("TestFuncT")] 15 | public class TestFuncT 16 | { 17 | [Test] 18 | public void FuncT() 19 | { 20 | SmartThreadPool stp = new SmartThreadPool(); 21 | IWorkItemResult wir = 22 | stp.QueueWorkItem(new Func(f), 1); 23 | 24 | int y = wir.GetResult(); 25 | 26 | Assert.AreEqual(y, 2); 27 | 28 | try 29 | { 30 | wir.GetResult(); 31 | } 32 | finally 33 | { 34 | stp.Shutdown(); 35 | } 36 | } 37 | 38 | private int f(int x) 39 | { 40 | return x + 1; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /STPTests/TestFuncT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | using NUnit.Framework; 4 | 5 | namespace SmartThreadPoolTests 6 | { 7 | /// 8 | /// Summary description for TestCancel. 9 | /// 10 | [TestFixture] 11 | [Category("TestFuncT")] 12 | public class TestFuncT 13 | { 14 | private SmartThreadPool _stp; 15 | 16 | [SetUp] 17 | public void Init() 18 | { 19 | _stp = new SmartThreadPool(); 20 | } 21 | 22 | [TearDown] 23 | public void Fini() 24 | { 25 | _stp.Shutdown(); 26 | } 27 | 28 | [Test] 29 | public void FuncT0() 30 | { 31 | IWorkItemResult wir = _stp.QueueWorkItem(new Func(MaxInt)); 32 | 33 | int result = wir.GetResult(); 34 | 35 | Assert.AreEqual(result, int.MaxValue); 36 | } 37 | 38 | [Test] 39 | public void FuncT1() 40 | { 41 | IWorkItemResult wir = _stp.QueueWorkItem(new Func(Not), true); 42 | 43 | bool result = wir.Result; 44 | 45 | Assert.AreEqual(result, false); 46 | } 47 | 48 | [Test] 49 | public void FuncT2() 50 | { 51 | IWorkItemResult wir = _stp.QueueWorkItem(new Func(string.Concat), "ABC", "xyz"); 52 | 53 | string result = wir.Result; 54 | 55 | Assert.AreEqual(result, "ABCxyz"); 56 | } 57 | 58 | [Test] 59 | public void FuncT3() 60 | { 61 | IWorkItemResult wir = _stp.QueueWorkItem(new Func(Substring), "ABCDEF", 1, 2); 62 | 63 | string result = wir.Result; 64 | 65 | Assert.AreEqual(result, "BC"); 66 | } 67 | 68 | [Test] 69 | public void FuncT4() 70 | { 71 | int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 72 | 73 | IWorkItemResult wir = _stp.QueueWorkItem(new Func(Subarray), numbers, 1, 2, 3); 74 | 75 | int[] result = wir.Result; 76 | 77 | Assert.AreEqual(result, new int[] { 2, 3, 2, 3, 2, 3, }); 78 | } 79 | 80 | private int MaxInt() 81 | { 82 | return int.MaxValue; 83 | } 84 | 85 | private bool Not(bool flag) 86 | { 87 | return !flag; 88 | } 89 | 90 | private string Substring(string s, int startIndex, int length) 91 | { 92 | return s.Substring(startIndex, length); 93 | } 94 | 95 | private int[] Subarray(int[] numbers, int startIndex, int length, int repeat) 96 | { 97 | int[] result = new int[length * repeat]; 98 | for (int i = 0; i < repeat; i++) 99 | { 100 | for (int j = 0; j < length; j++) 101 | { 102 | result[i * length + j] = numbers[startIndex + j]; 103 | } 104 | } 105 | 106 | return result; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /STPTests/TestGetResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace SmartThreadPoolTests 9 | { 10 | /// 11 | /// Summary description for GetResultExample. 12 | /// 13 | [TestFixture] 14 | [Category("TestGetResult")] 15 | public class TestGetResult 16 | { 17 | /// 18 | /// Example of how to queue a work item and then wait infinitely for the result. 19 | /// 20 | [Test] 21 | public void BlockingCall() 22 | { 23 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 24 | 25 | bool success = false; 26 | 27 | IWorkItemResult wir = 28 | smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 29 | 30 | if (!wir.IsCompleted) 31 | { 32 | int result = (int)wir.GetResult(); 33 | success = (1 == result); 34 | } 35 | 36 | smartThreadPool.Shutdown(); 37 | 38 | Assert.IsTrue(success); 39 | } 40 | 41 | /// 42 | /// Example of how to queue a work item and then wait on a timeout for the result. 43 | /// 44 | [Test] 45 | public void Timeout() 46 | { 47 | Assert.Throws(() => 48 | { 49 | 50 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 51 | 52 | IWorkItemResult wir = 53 | smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 54 | 55 | try 56 | { 57 | wir.GetResult(500, true); 58 | } 59 | finally 60 | { 61 | smartThreadPool.Shutdown(); 62 | } 63 | }); 64 | } 65 | 66 | /// 67 | /// Example of how to interrupt the waiting for a work item to complete. 68 | /// 69 | [Test] 70 | public void WorkItemWaitCanceling() 71 | { 72 | Assert.Throws(() => 73 | { 74 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 75 | 76 | ManualResetEvent cancelWaitHandle = new ManualResetEvent(false); 77 | 78 | // Queue a work item that will occupy the thread in the pool 79 | IWorkItemResult wir1 = 80 | smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 81 | 82 | // Queue another work item that will wait for the first to complete 83 | IWorkItemResult wir2 = 84 | smartThreadPool.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle); 85 | 86 | try 87 | { 88 | wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle); 89 | } 90 | finally 91 | { 92 | smartThreadPool.Shutdown(); 93 | } 94 | }); 95 | } 96 | 97 | private object DoSomeWork(object state) 98 | { 99 | Thread.Sleep(1000); 100 | return 1; 101 | } 102 | 103 | private object SignalCancel(object state) 104 | { 105 | ManualResetEvent cancelWaitHandle = state as ManualResetEvent; 106 | Thread.Sleep(250); 107 | cancelWaitHandle.Set(); 108 | return null; 109 | } 110 | 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /STPTests/TestParallelMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace SmartThreadPoolTests 9 | { 10 | /// 11 | /// Summary description for TestParallelMethods. 12 | /// 13 | [TestFixture] 14 | [Category("TestParallelMethods")] 15 | public class TestParallelMethods 16 | { 17 | [Test] 18 | public void TestJoin() 19 | { 20 | SmartThreadPool stp = new SmartThreadPool(); 21 | 22 | SafeCounter sc = new SafeCounter(); 23 | 24 | stp.Join( 25 | sc.Increment, 26 | sc.Increment, 27 | sc.Increment); 28 | 29 | Assert.AreEqual(3, sc.Counter); 30 | 31 | for (int j = 0; j < 10; j++) 32 | { 33 | sc.Reset(); 34 | 35 | Action[] actions = new Action[1000]; 36 | for (int i = 0; i < actions.Length; i++) 37 | { 38 | actions[i] = sc.Increment; 39 | } 40 | 41 | stp.Join(actions); 42 | 43 | Assert.AreEqual(actions.Length, sc.Counter); 44 | } 45 | 46 | stp.Shutdown(); 47 | } 48 | 49 | private class SafeCounter 50 | { 51 | private int _counter; 52 | 53 | public void Increment() 54 | { 55 | Interlocked.Increment(ref _counter); 56 | } 57 | 58 | public int Counter 59 | { 60 | get { return _counter; } 61 | } 62 | 63 | public void Reset() 64 | { 65 | _counter = 0; 66 | } 67 | } 68 | 69 | [Test] 70 | public void TestChoice() 71 | { 72 | SmartThreadPool stp = new SmartThreadPool(); 73 | 74 | int index = stp.Choice( 75 | () => Thread.Sleep(1000), 76 | () => Thread.Sleep(1500), 77 | () => Thread.Sleep(500)); 78 | 79 | Assert.AreEqual(2, index); 80 | 81 | index = stp.Choice( 82 | () => Thread.Sleep(300), 83 | () => Thread.Sleep(100), 84 | () => Thread.Sleep(200)); 85 | 86 | Assert.AreEqual(1, index); 87 | 88 | stp.Shutdown(); 89 | } 90 | 91 | [Test] 92 | public void TestPipe() 93 | { 94 | SafeCounter sc = new SafeCounter(); 95 | SmartThreadPool stp = new SmartThreadPool(); 96 | 97 | stp.Pipe( 98 | sc, 99 | sc1 => { if (sc.Counter == 0) { sc1.Increment(); }}, 100 | sc1 => { if (sc.Counter == 1) { sc1.Increment(); }}, 101 | sc1 => { if (sc.Counter == 2) { sc1.Increment(); }} 102 | ); 103 | 104 | Assert.AreEqual(3, sc.Counter); 105 | 106 | stp.Shutdown(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /STPTests/TestPriorityQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | using Amib.Threading.Internal; 7 | using SmartThreadPoolTests; 8 | 9 | namespace PriorityQueueTests 10 | { 11 | /// 12 | /// Summary description for TestPriorityQueue. 13 | /// 14 | [TestFixture] 15 | [Category("TestPriorityQueue")] 16 | public class TestPriorityQueue 17 | { 18 | [Test] 19 | public void Init() 20 | { 21 | PriorityQueue pq = new PriorityQueue(); 22 | 23 | Assert.AreEqual(0, pq.Count); 24 | 25 | Assert.IsNull(pq.Dequeue()); 26 | 27 | Assert.AreEqual(0, pq.Count); 28 | } 29 | 30 | [Test] 31 | public void OneWorkItem() 32 | { 33 | WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority []; 34 | foreach(WorkItemPriority wip in priorities) 35 | { 36 | PriorityQueue pq = new PriorityQueue(); 37 | 38 | PriorityItem pi = new PriorityItem(wip); 39 | 40 | pq.Enqueue(pi); 41 | 42 | Assert.AreEqual(1, pq.Count, "Failed for priority {0}", wip); 43 | 44 | PriorityItem pi2 = pq.Dequeue() as PriorityItem; 45 | 46 | Assert.IsNotNull(pi2, "Failed for priority {0}", wip); 47 | 48 | Assert.AreSame(pi, pi2, "Failed for priority {0}", wip); 49 | 50 | Assert.AreEqual(0, pq.Count, "Failed for priority {0}", wip); 51 | } 52 | } 53 | 54 | [Test] 55 | public void MultipleWorkItemsOnePriority() 56 | { 57 | WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority []; 58 | foreach(WorkItemPriority wip in priorities) 59 | { 60 | PriorityQueue pq = new PriorityQueue(); 61 | 62 | PriorityItem [] priorityItems = new PriorityItem[10]; 63 | 64 | for(int i = 0; i < priorityItems.Length; ++i) 65 | { 66 | priorityItems[i] = new PriorityItem(wip); 67 | 68 | pq.Enqueue(priorityItems[i]); 69 | 70 | Assert.AreEqual(i+1, pq.Count, "Failed for priority {0} item count {1}", wip, i+1); 71 | } 72 | 73 | for(int i = 0; i < priorityItems.Length; ++i) 74 | { 75 | PriorityItem pi = pq.Dequeue() as PriorityItem; 76 | 77 | Assert.AreEqual(priorityItems.Length-(i+1), pq.Count, "Failed for priority {0} item count {1}", wip, i+1); 78 | 79 | Assert.IsNotNull(pi, "Failed for priority {0} item count {1}", wip, i+1); 80 | 81 | Assert.AreSame(pi, priorityItems[i], "Failed for priority {0} item count {1}", wip, i+1); 82 | } 83 | 84 | Assert.AreEqual(0, pq.Count, "Failed for priority {0}", wip); 85 | 86 | Assert.IsNull(pq.Dequeue()); 87 | 88 | Assert.AreEqual(0, pq.Count); 89 | } 90 | } 91 | 92 | [Test] 93 | public void MultipleWorkItemsMultiplePriorities() 94 | { 95 | // Get all the available priorities 96 | WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority []; 97 | 98 | // Create an array of priority items 99 | PriorityItem [] priorityItems = new PriorityItem[priorities.Length]; 100 | 101 | // Create a priority item for each priority 102 | int i = priorities.Length; 103 | foreach(WorkItemPriority workItemPriority in priorities) 104 | { 105 | --i; 106 | priorityItems[i] = new PriorityItem(workItemPriority); 107 | } 108 | 109 | // Create a PermutationGenerator for the priority items 110 | PermutationGenerator permutations = new PermutationGenerator(priorityItems); 111 | 112 | int count = 0; 113 | // Iterate over the permutations 114 | foreach(object [] permutation in permutations) 115 | { 116 | ++count; 117 | Console.Write("Permutation #" + count + " : "); 118 | for(int j = 0; j < permutation.Length; ++j) 119 | { 120 | PriorityItem pi = permutation[j] as PriorityItem; 121 | Console.Write(pi.WorkItemPriority + ", "); 122 | } 123 | Console.WriteLine(); 124 | // Create a priority queue 125 | PriorityQueue pq = new PriorityQueue(); 126 | 127 | // Enqueue each priority item according to the permutation 128 | for(i = 0; i < permutation.Length; ++i) 129 | { 130 | PriorityItem priorityItem = permutation[i] as PriorityItem; 131 | pq.Enqueue(priorityItem); 132 | } 133 | 134 | // Make sure all the priority items are in the queue 135 | Assert.AreEqual(priorityItems.Length, pq.Count); 136 | 137 | // Compare the order of the priority items 138 | for(i = 0; i < priorityItems.Length; ++i) 139 | { 140 | PriorityItem priorityItem = pq.Dequeue() as PriorityItem; 141 | Assert.AreSame(priorityItems[i], priorityItem); 142 | } 143 | } 144 | } 145 | 146 | private class PriorityItem : IHasWorkItemPriority 147 | { 148 | public PriorityItem(WorkItemPriority workItemPriority) 149 | { 150 | WorkItemPriority = workItemPriority; 151 | } 152 | 153 | public WorkItemPriority WorkItemPriority { get; private set; } 154 | } 155 | 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /STPTests/TestQueueWorkItem.cs: -------------------------------------------------------------------------------- 1 | 2 | using NUnit.Framework; 3 | using Amib.Threading; 4 | 5 | namespace SmartThreadPoolTests 6 | { 7 | /// 8 | /// Tests for QueueWorkItem. 9 | /// 10 | [TestFixture] 11 | [Category("TestQueueWorkItem")] 12 | public class TestQueueWorkItem 13 | { 14 | private SmartThreadPool _stp; 15 | 16 | [SetUp] 17 | public void Init() 18 | { 19 | _stp = new SmartThreadPool(); 20 | } 21 | 22 | [TearDown] 23 | public void Fini() 24 | { 25 | _stp.Shutdown(); 26 | } 27 | 28 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback); 29 | [Test] 30 | public void TestQueueWorkItemCall() 31 | { 32 | QueueWorkItemHelper.TestQueueWorkItemCall(_stp); 33 | } 34 | 35 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); 36 | [Test] 37 | public void TestQueueWorkItemCallPrio() 38 | { 39 | QueueWorkItemHelper.TestQueueWorkItemCallPrio(_stp); 40 | } 41 | 42 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); 43 | [Test] 44 | public void TestQueueWorkItemCallStat() 45 | { 46 | QueueWorkItemHelper.TestQueueWorkItemCallStat(_stp); 47 | } 48 | 49 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); 50 | [Test] 51 | public void TestQueueWorkItemCallStatPrio() 52 | { 53 | QueueWorkItemHelper.TestQueueWorkItemCallStatPrio(_stp); 54 | } 55 | 56 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); 57 | [Test] 58 | public void TestQueueWorkItemCallStatPost() 59 | { 60 | QueueWorkItemHelper.TestQueueWorkItemCallStatPost(_stp); 61 | } 62 | 63 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); 64 | [Test] 65 | public void TestQueueWorkItemCallStatPostPrio() 66 | { 67 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPrio(_stp); 68 | } 69 | 70 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); 71 | [Test] 72 | public void TestQueueWorkItemCallStatPostPflg() 73 | { 74 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflg(_stp); 75 | } 76 | 77 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); 78 | [Test] 79 | public void TestQueueWorkItemCallStatPostPflgPrio() 80 | { 81 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflgPrio(_stp); 82 | } 83 | 84 | //IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); 85 | [Test] 86 | public void TestQueueWorkItemInfoCall() 87 | { 88 | QueueWorkItemHelper.TestQueueWorkItemInfoCall(_stp); 89 | } 90 | 91 | //IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); 92 | [Test] 93 | public void TestQueueWorkItemInfoCallStat() 94 | { 95 | QueueWorkItemHelper.TestQueueWorkItemInfoCallStat(_stp); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /STPTests/TestStartSuspended.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace SmartThreadPoolTests 8 | { 9 | /// 10 | /// Summary description for TestStartSuspended. 11 | /// 12 | [TestFixture] 13 | [Category("TestStartSuspended")] 14 | public class TestStartSuspended 15 | { 16 | [Test] 17 | public void StartSuspended() 18 | { 19 | STPStartInfo stpStartInfo = new STPStartInfo(); 20 | stpStartInfo.StartSuspended = true; 21 | 22 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 23 | 24 | stp.QueueWorkItem(new WorkItemCallback(this.DoWork)); 25 | 26 | Assert.IsFalse(stp.WaitForIdle(200)); 27 | 28 | stp.Start(); 29 | 30 | Assert.IsTrue(stp.WaitForIdle(200)); 31 | } 32 | 33 | [Test] 34 | public void WIGStartSuspended() 35 | { 36 | SmartThreadPool stp = new SmartThreadPool(); 37 | 38 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 39 | wigStartInfo.StartSuspended = true; 40 | 41 | IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10, wigStartInfo); 42 | 43 | wig.QueueWorkItem(new WorkItemCallback(this.DoWork)); 44 | 45 | Assert.IsFalse(wig.WaitForIdle(200)); 46 | 47 | wig.Start(); 48 | 49 | Assert.IsTrue(wig.WaitForIdle(200)); 50 | } 51 | 52 | [Test] 53 | public void STPAndWIGStartSuspended() 54 | { 55 | STPStartInfo stpStartInfo = new STPStartInfo(); 56 | stpStartInfo.StartSuspended = true; 57 | 58 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 59 | 60 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 61 | wigStartInfo.StartSuspended = true; 62 | 63 | IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10, wigStartInfo); 64 | 65 | wig.QueueWorkItem(new WorkItemCallback(this.DoWork)); 66 | 67 | Assert.IsFalse(wig.WaitForIdle(200)); 68 | 69 | wig.Start(); 70 | 71 | Assert.IsFalse(wig.WaitForIdle(200)); 72 | 73 | stp.Start(); 74 | 75 | Assert.IsTrue(wig.WaitForIdle(5000), "WIG is not idle"); 76 | Assert.IsTrue(stp.WaitForIdle(5000), "STP is not idle"); 77 | } 78 | 79 | [Test] 80 | public void TwoWIGsStartSuspended() 81 | { 82 | SmartThreadPool stp = new SmartThreadPool(); 83 | 84 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 85 | wigStartInfo.StartSuspended = true; 86 | 87 | IWorkItemsGroup wig1 = stp.CreateWorkItemsGroup(10, wigStartInfo); 88 | IWorkItemsGroup wig2 = stp.CreateWorkItemsGroup(10, wigStartInfo); 89 | 90 | wig1.QueueWorkItem(new WorkItemCallback(this.DoWork)); 91 | wig2.QueueWorkItem(new WorkItemCallback(this.DoWork)); 92 | 93 | Assert.IsFalse(wig1.WaitForIdle(200)); 94 | Assert.IsFalse(wig2.WaitForIdle(200)); 95 | 96 | wig1.Start(); 97 | 98 | Assert.IsTrue(wig1.WaitForIdle(200)); 99 | Assert.IsFalse(wig2.WaitForIdle(200)); 100 | 101 | wig2.Start(); 102 | 103 | Assert.IsTrue(wig1.WaitForIdle(0)); 104 | Assert.IsTrue(wig2.WaitForIdle(200)); 105 | } 106 | 107 | 108 | private object DoWork(object state) 109 | { 110 | Thread.Sleep(100); 111 | return null; 112 | } 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /STPTests/TestStateDispose.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace SmartThreadPoolTests 9 | { 10 | public class CallerState 11 | { 12 | public int Value { get; private set; } 13 | 14 | protected void IncValue() 15 | { 16 | ++Value; 17 | } 18 | } 19 | 20 | public class NonDisposableCallerState : CallerState 21 | { 22 | public NonDisposableCallerState() 23 | { 24 | IncValue(); 25 | } 26 | } 27 | 28 | public class DisposableCallerState : CallerState, IDisposable 29 | { 30 | public DisposableCallerState() 31 | { 32 | IncValue(); 33 | } 34 | 35 | #region IDisposable Members 36 | 37 | public void Dispose() 38 | { 39 | IncValue(); 40 | } 41 | 42 | #endregion 43 | } 44 | 45 | 46 | /// 47 | /// Summary description for StateDisposeExample. 48 | /// 49 | [TestFixture] 50 | [Category("TestStateDispose")] 51 | public class TestStateDispose 52 | { 53 | /// 54 | /// Example of non disposable caller state 55 | /// 56 | [Test] 57 | public void DisposeCallerState() 58 | { 59 | STPStartInfo stpStartInfo = new STPStartInfo(); 60 | stpStartInfo.DisposeOfStateObjects = true; 61 | 62 | SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo); 63 | 64 | CallerState nonDisposableCallerState = new NonDisposableCallerState(); 65 | CallerState disposableCallerState = new DisposableCallerState(); 66 | 67 | IWorkItemResult wir1 = 68 | smartThreadPool.QueueWorkItem( 69 | new WorkItemCallback(this.DoSomeWork), 70 | nonDisposableCallerState); 71 | 72 | IWorkItemResult wir2 = 73 | smartThreadPool.QueueWorkItem( 74 | new WorkItemCallback(this.DoSomeWork), 75 | disposableCallerState); 76 | 77 | wir1.GetResult(); 78 | Assert.AreEqual(1, nonDisposableCallerState.Value); 79 | 80 | wir2.GetResult(); 81 | 82 | // Wait a little bit for the working thread to call dispose on the 83 | // work item's state. 84 | smartThreadPool.WaitForIdle(); 85 | 86 | Assert.AreEqual(2, disposableCallerState.Value); 87 | 88 | smartThreadPool.Shutdown(); 89 | } 90 | 91 | /// 92 | /// Example of non disposable caller state 93 | /// 94 | [Test] 95 | public void DontDisposeCallerState() 96 | { 97 | STPStartInfo stpStartInfo = new STPStartInfo(); 98 | stpStartInfo.DisposeOfStateObjects = false; 99 | 100 | SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo); 101 | 102 | CallerState nonDisposableCallerState = new NonDisposableCallerState(); 103 | CallerState disposableCallerState = new DisposableCallerState(); 104 | 105 | IWorkItemResult wir1 = 106 | smartThreadPool.QueueWorkItem( 107 | new WorkItemCallback(this.DoSomeWork), 108 | nonDisposableCallerState); 109 | 110 | IWorkItemResult wir2 = 111 | smartThreadPool.QueueWorkItem( 112 | new WorkItemCallback(this.DoSomeWork), 113 | disposableCallerState); 114 | 115 | wir1.GetResult(); 116 | bool success = (1 == nonDisposableCallerState.Value); 117 | 118 | wir2.GetResult(); 119 | 120 | success = success && (1 == disposableCallerState.Value); 121 | 122 | smartThreadPool.Shutdown(); 123 | 124 | Assert.IsTrue(success); 125 | } 126 | 127 | private object DoSomeWork(object state) 128 | { 129 | Thread.Sleep(1000); 130 | return 1; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /STPTests/TestThreadApartmentState.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using NUnit.Framework; 3 | using Amib.Threading; 4 | 5 | namespace SmartThreadPoolTests 6 | { 7 | /// 8 | /// Summary description for TestThreadApartment. 9 | /// 10 | [TestFixture] 11 | [Category("TestThreadApartment")] 12 | public class TestThreadApartmentState 13 | { 14 | [Test] 15 | public void TestSTA() 16 | { 17 | CheckApartmentState(ApartmentState.STA); 18 | } 19 | 20 | [Test] 21 | public void TestMTA() 22 | { 23 | CheckApartmentState(ApartmentState.MTA); 24 | } 25 | 26 | private static void CheckApartmentState(ApartmentState requestApartmentState) 27 | { 28 | STPStartInfo stpStartInfo = new STPStartInfo(); 29 | stpStartInfo.ApartmentState = requestApartmentState; 30 | 31 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 32 | 33 | IWorkItemResult wir = stp.QueueWorkItem(() => GetCurrentThreadApartmentState()); 34 | 35 | ApartmentState resultApartmentState = wir.GetResult(); 36 | 37 | stp.WaitForIdle(); 38 | 39 | Assert.AreEqual(requestApartmentState, resultApartmentState); 40 | } 41 | 42 | private static ApartmentState GetCurrentThreadApartmentState() 43 | { 44 | return Thread.CurrentThread.GetApartmentState(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /STPTests/TestThreadIsBackground.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using NUnit.Framework; 3 | using Amib.Threading; 4 | 5 | namespace SmartThreadPoolTests 6 | { 7 | /// 8 | /// Summary description for TestThreadIsBackground. 9 | /// 10 | [TestFixture] 11 | [Category("TestThreadIsBackground")] 12 | public class TestThreadIsBackground 13 | { 14 | [Test] 15 | public void TestIsBackground() 16 | { 17 | CheckIsBackground(true); 18 | } 19 | 20 | [Test] 21 | public void TestNotIsBackground() 22 | { 23 | CheckIsBackground(false); 24 | } 25 | 26 | private static void CheckIsBackground(bool isBackground) 27 | { 28 | STPStartInfo stpStartInfo = new STPStartInfo(); 29 | stpStartInfo.AreThreadsBackground = isBackground; 30 | 31 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 32 | 33 | IWorkItemResult wir = stp.QueueWorkItem(() => GetCurrentThreadIsBackground()); 34 | 35 | bool resultIsBackground = wir.GetResult(); 36 | 37 | stp.WaitForIdle(); 38 | 39 | Assert.AreEqual(isBackground, resultIsBackground); 40 | } 41 | 42 | private static bool GetCurrentThreadIsBackground() 43 | { 44 | return Thread.CurrentThread.IsBackground; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /STPTests/TestThreadPriority.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Threading; 4 | 5 | using NUnit.Framework; 6 | 7 | using Amib.Threading; 8 | 9 | namespace SmartThreadPoolTests 10 | { 11 | /// 12 | /// Summary description for TestThreadPriority. 13 | /// 14 | [TestFixture] 15 | [Category("TestThreadPriority")] 16 | public class TestThreadPriority 17 | { 18 | [Test] 19 | public void TestDefaultPriority() 20 | { 21 | CheckSinglePriority(SmartThreadPool.DefaultThreadPriority); 22 | } 23 | 24 | [Test] 25 | public void TestLowestPriority() 26 | { 27 | CheckSinglePriority(ThreadPriority.Lowest); 28 | } 29 | 30 | [Test] 31 | public void TestBelowNormalPriority() 32 | { 33 | CheckSinglePriority(ThreadPriority.BelowNormal); 34 | } 35 | 36 | [Test] 37 | public void TestNormalPriority() 38 | { 39 | CheckSinglePriority(ThreadPriority.BelowNormal); 40 | } 41 | 42 | [Test] 43 | public void TestAboveNormalPriority() 44 | { 45 | CheckSinglePriority(ThreadPriority.AboveNormal); 46 | } 47 | 48 | [Test] 49 | public void TestHighestPriority() 50 | { 51 | CheckSinglePriority(ThreadPriority.Highest); 52 | } 53 | 54 | private void CheckSinglePriority(ThreadPriority threadPriority) 55 | { 56 | STPStartInfo stpStartInfo = new STPStartInfo(); 57 | stpStartInfo.ThreadPriority = threadPriority; 58 | 59 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 60 | 61 | IWorkItemResult wir = stp.QueueWorkItem(new WorkItemCallback(GetThreadPriority)); 62 | ThreadPriority currentThreadPriority = (ThreadPriority)wir.GetResult(); 63 | 64 | Assert.AreEqual(threadPriority, currentThreadPriority); 65 | } 66 | 67 | private object GetThreadPriority(object state) 68 | { 69 | return Thread.CurrentThread.Priority; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /STPTests/TestThreadsCreate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace SmartThreadPoolTests 8 | { 9 | /// 10 | /// 11 | [TestFixture] 12 | [Category("TestThreadsCreate")] 13 | public class TestThreadsCreate 14 | { 15 | private bool _initSuccess; 16 | private bool _workItemSuccess; 17 | private bool _termSuccess; 18 | 19 | private void ClearResults() 20 | { 21 | _initSuccess = false; 22 | _workItemSuccess = false; 23 | _termSuccess = false; 24 | } 25 | 26 | [Test] 27 | public void TestThreadsEvents() 28 | { 29 | ClearResults(); 30 | 31 | SmartThreadPool stp = new SmartThreadPool(1000); 32 | 33 | stp.OnThreadInitialization += OnInitialization; 34 | stp.OnThreadTermination += OnTermination; 35 | 36 | stp.QueueWorkItem(new WorkItemCallback(DoSomeWork), null); 37 | 38 | stp.WaitForIdle(); 39 | 40 | // .net core Thread.Abort is not supported, so wait for the thread to go idle and self terminate 41 | stp.Shutdown(Timeout.Infinite); 42 | 43 | Assert.IsTrue(_initSuccess); 44 | Assert.IsTrue(_workItemSuccess); 45 | Assert.IsTrue(_termSuccess); 46 | } 47 | 48 | #if (NETFRAMEWORK) 49 | 50 | [Test] 51 | public void TestThreadsEventsWithAbort() 52 | { 53 | ClearResults(); 54 | 55 | SmartThreadPool stp = new SmartThreadPool(1000); 56 | 57 | stp.OnThreadInitialization += OnInitialization; 58 | stp.OnThreadTermination += OnTermination; 59 | 60 | stp.QueueWorkItem(new WorkItemCallback(DoSomeWork), null); 61 | 62 | stp.WaitForIdle(); 63 | 64 | stp.Shutdown(true); 65 | 66 | Assert.IsTrue(_initSuccess); 67 | Assert.IsTrue(_workItemSuccess); 68 | Assert.IsTrue(_termSuccess); 69 | } 70 | #endif 71 | public void OnInitialization() 72 | { 73 | ThreadContextState.Current.Counter = 1234; 74 | _initSuccess = true; 75 | } 76 | 77 | private object DoSomeWork(object state) 78 | { 79 | int counter = ThreadContextState.Current.Counter; 80 | _workItemSuccess = (1234 == counter); 81 | 82 | ThreadContextState.Current.Counter = 1111; 83 | return 1; 84 | } 85 | 86 | public void OnTermination() 87 | { 88 | int counter = ThreadContextState.Current.Counter; 89 | _termSuccess = (1111 == counter); 90 | } 91 | 92 | 93 | // Can't run this test, StackOverflowException crashes the application and can't be caught and ignored 94 | //[Test] 95 | public void NotTestThreadsMaxStackSize() 96 | { 97 | STPStartInfo stpStartInfo = new STPStartInfo() 98 | { 99 | MaxStackSize = 64 * 1024, 100 | }; 101 | 102 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 103 | stp.Start(); 104 | 105 | IWorkItemResult wir = stp.QueueWorkItem(() => AllocateBufferOnStack(10 * 1024)); 106 | 107 | bool result = wir.GetResult(); 108 | Assert.IsTrue(result); 109 | 110 | wir = stp.QueueWorkItem(() => AllocateBufferOnStack(1000 * 1024)); 111 | 112 | result = wir.GetResult(); 113 | Assert.IsFalse(result); 114 | } 115 | 116 | private static unsafe bool AllocateBufferOnStack(int size) 117 | { 118 | try 119 | { 120 | byte* p = stackalloc byte[size]; 121 | } 122 | catch (StackOverflowException) 123 | { 124 | return false; 125 | } 126 | catch (Exception) 127 | { 128 | return false; 129 | } 130 | 131 | return true; 132 | } 133 | } 134 | 135 | internal class ThreadContextState 136 | { 137 | // Each thread will have its own ThreadContextState object 138 | [ThreadStatic] 139 | private static ThreadContextState _threadContextState; 140 | 141 | public int Counter { get; set; } 142 | 143 | // Static member so it can be used anywhere in code of the work item method 144 | public static ThreadContextState Current 145 | { 146 | get 147 | { 148 | // If the _threadContextState is null then it was not yet initialized 149 | // for this thread. 150 | if (null == _threadContextState) 151 | { 152 | // Create a ThreadContextState object 153 | _threadContextState = new ThreadContextState(); 154 | } 155 | return _threadContextState; 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /STPTests/TestWIGActionT.cs: -------------------------------------------------------------------------------- 1 | using Amib.Threading; 2 | using NUnit.Framework; 3 | 4 | namespace WorkItemsGroupTests 5 | { 6 | /// 7 | /// Summary description for TestCancel. 8 | /// 9 | [TestFixture] 10 | [Category("TestWIGActionT")] 11 | public class TestWIGActionT 12 | { 13 | private SmartThreadPool _stp; 14 | private IWorkItemsGroup _wig; 15 | private object _result; 16 | 17 | [SetUp] 18 | public void Init() 19 | { 20 | _stp = new SmartThreadPool(); 21 | _wig = _stp.CreateWorkItemsGroup(10); 22 | } 23 | 24 | [TearDown] 25 | public void Fini() 26 | { 27 | _stp.Shutdown(); 28 | } 29 | 30 | [Test] 31 | public void ActionT0() 32 | { 33 | _result = null; 34 | 35 | IWorkItemResult wir = _wig.QueueWorkItem(MaxInt); 36 | 37 | wir.GetResult(); 38 | 39 | Assert.AreEqual(_result, int.MaxValue); 40 | } 41 | 42 | [Test] 43 | public void ActionT1() 44 | { 45 | _result = null; 46 | 47 | IWorkItemResult wir = _wig.QueueWorkItem(Not, true); 48 | 49 | wir.GetResult(); 50 | 51 | Assert.AreEqual(_result, false); 52 | } 53 | 54 | [Test] 55 | public void ActionT2() 56 | { 57 | _result = null; 58 | 59 | IWorkItemResult wir = _wig.QueueWorkItem(Concat, "ABC", "xyz"); 60 | 61 | wir.GetResult(); 62 | 63 | Assert.AreEqual(_result, "ABCxyz"); 64 | } 65 | 66 | [Test] 67 | public void ActionT3() 68 | { 69 | _result = null; 70 | 71 | IWorkItemResult wir = _wig.QueueWorkItem(Substring, "ABCDEF", 1, 2); 72 | 73 | wir.GetResult(); 74 | 75 | Assert.AreEqual(_result, "BC"); 76 | } 77 | 78 | [Test] 79 | public void ActionT4() 80 | { 81 | _result = null; 82 | 83 | int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 84 | 85 | IWorkItemResult wir = _wig.QueueWorkItem(Subarray, numbers, 1, 2, 3); 86 | 87 | wir.GetResult(); 88 | 89 | Assert.AreEqual(_result, new int[] { 2, 3, 2, 3, 2, 3, }); 90 | } 91 | 92 | private void MaxInt() 93 | { 94 | _result = int.MaxValue; 95 | } 96 | 97 | private void Not(bool flag) 98 | { 99 | _result = !flag; 100 | } 101 | 102 | private void Concat(string s1, string s2) 103 | { 104 | _result = s1 + s2; 105 | } 106 | 107 | private void Substring(string s, int startIndex, int length) 108 | { 109 | _result = s.Substring(startIndex, length); 110 | } 111 | 112 | private void Subarray(int[] numbers, int startIndex, int length, int repeat) 113 | { 114 | int[] result = new int[length * repeat]; 115 | for (int i = 0; i < repeat; i++) 116 | { 117 | for (int j = 0; j < length; j++) 118 | { 119 | result[i * length + j] = numbers[startIndex + j]; 120 | } 121 | } 122 | 123 | _result = result; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /STPTests/TestWIGChainedDelegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | using Amib.Threading; 5 | 6 | namespace WorkItemsGroupTests 7 | { 8 | /// 9 | /// Summary description for TestChainedDelegates. 10 | /// 11 | [TestFixture] 12 | [Category("Test WorkItemsGroup ChainedDelegates")] 13 | public class TestChainedDelegates 14 | { 15 | [Test] 16 | public void GoodCallback() 17 | { 18 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 19 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 20 | 21 | workItemsGroup.QueueWorkItem(new WorkItemCallback(DoWork)); 22 | 23 | workItemsGroup.WaitForIdle(); 24 | 25 | smartThreadPool.Shutdown(); 26 | } 27 | 28 | [Test] 29 | public void ChainedDelegatesCallback() 30 | { 31 | Assert.Throws(() => 32 | { 33 | 34 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 35 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 36 | 37 | WorkItemCallback workItemCallback = new WorkItemCallback(DoWork); 38 | workItemCallback += new WorkItemCallback(DoWork); 39 | 40 | workItemsGroup.QueueWorkItem(workItemCallback); 41 | 42 | workItemsGroup.WaitForIdle(); 43 | 44 | smartThreadPool.Shutdown(); 45 | }); 46 | } 47 | 48 | [Test] 49 | public void GoodPostExecute() 50 | { 51 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 52 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 53 | 54 | workItemsGroup.QueueWorkItem( 55 | new WorkItemCallback(DoWork), 56 | null, 57 | new PostExecuteWorkItemCallback(DoPostExecute)); 58 | 59 | workItemsGroup.WaitForIdle(); 60 | 61 | smartThreadPool.Shutdown(); 62 | } 63 | 64 | [Test] 65 | public void ChainedDelegatesPostExecute() 66 | { 67 | Assert.Throws(() => 68 | { 69 | 70 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 71 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 72 | 73 | PostExecuteWorkItemCallback postExecuteWorkItemCallback = 74 | new PostExecuteWorkItemCallback(DoPostExecute); 75 | postExecuteWorkItemCallback += 76 | new PostExecuteWorkItemCallback(DoPostExecute); 77 | 78 | workItemsGroup.QueueWorkItem( 79 | new WorkItemCallback(DoWork), 80 | null, 81 | postExecuteWorkItemCallback); 82 | 83 | workItemsGroup.WaitForIdle(); 84 | 85 | smartThreadPool.Shutdown(); 86 | }); 87 | } 88 | 89 | 90 | private object DoWork(object state) 91 | { 92 | return null; 93 | } 94 | 95 | private void DoPostExecute(IWorkItemResult wir) 96 | { 97 | } 98 | 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /STPTests/TestWIGConcurrency.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace WorkItemsGroupTests 9 | { 10 | /// 11 | /// Summary description for TestWIGConcurrency. 12 | /// 13 | [TestFixture] 14 | [Category("TestWIGConcurrency")] 15 | public class TestWIGConcurrency 16 | { 17 | private Random _randGen; 18 | private int [] _concurrentOps; 19 | private int _concurrencyPerWig; 20 | private bool _success; 21 | 22 | [Test] 23 | public void TestConcurrencies() 24 | { 25 | Concurrency(1, 1, 10); 26 | Concurrency(1, 1, 100); 27 | 28 | Concurrency(1, 5, 10); 29 | Concurrency(1, 5, 100); 30 | 31 | Concurrency(5, 5, 10); 32 | Concurrency(5, 5, 100); 33 | } 34 | 35 | private void Concurrency( 36 | int concurrencyPerWig, 37 | int wigsCount, 38 | int workItemsCount) 39 | { 40 | Console.WriteLine( 41 | "Testing : concurrencyPerWig = {0}, wigsCount = {1}, workItemsCount = {2}", 42 | concurrencyPerWig, 43 | wigsCount, 44 | workItemsCount); 45 | 46 | _success = true; 47 | _concurrencyPerWig = concurrencyPerWig; 48 | _randGen = new Random(0); 49 | 50 | STPStartInfo stpStartInfo = new STPStartInfo(); 51 | stpStartInfo.StartSuspended = true; 52 | 53 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 54 | 55 | _concurrentOps = new int[wigsCount]; 56 | 57 | IWorkItemsGroup [] wigs = new IWorkItemsGroup[wigsCount]; 58 | 59 | for(int i = 0; i < wigs.Length; ++i) 60 | { 61 | wigs[i] = stp.CreateWorkItemsGroup(_concurrencyPerWig); 62 | for(int j = 0; j < workItemsCount; ++j) 63 | { 64 | wigs[i].QueueWorkItem(new WorkItemCallback(this.DoWork), i); 65 | } 66 | 67 | wigs[i].Start(); 68 | } 69 | 70 | stp.Start(); 71 | 72 | stp.WaitForIdle(); 73 | 74 | Assert.IsTrue(_success); 75 | 76 | stp.Shutdown(); 77 | } 78 | 79 | private object DoWork(object state) 80 | { 81 | int wigsIndex = (int)state; 82 | 83 | int val = Interlocked.Increment(ref _concurrentOps[wigsIndex]); 84 | _success = _success && (val <= _concurrencyPerWig); 85 | 86 | int waitTime = _randGen.Next(50); 87 | Thread.Sleep(waitTime); 88 | 89 | val = Interlocked.Decrement(ref _concurrentOps[wigsIndex]); 90 | _success = _success && (val >= 0); 91 | 92 | return null; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /STPTests/TestWIGExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace WorkItemsGroupTests 8 | { 9 | /// 10 | /// Summary description for TestExceptions. 11 | /// 12 | [TestFixture] 13 | [Category("Test WorkItemsGroup Exceptions")] 14 | public class TestExceptions 15 | { 16 | private class DivArgs 17 | { 18 | public int x; 19 | public int y; 20 | } 21 | 22 | [Test] 23 | public void ExceptionThrowing() 24 | { 25 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 26 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 27 | 28 | DivArgs divArgs = new DivArgs(); 29 | divArgs.x = 10; 30 | divArgs.y = 0; 31 | 32 | IWorkItemResult wir = 33 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs); 34 | 35 | try 36 | { 37 | wir.GetResult(); 38 | } 39 | catch(WorkItemResultException wire) 40 | { 41 | Assert.IsTrue(wire.InnerException is DivideByZeroException); 42 | return; 43 | } 44 | catch(Exception e) 45 | { 46 | e.GetHashCode(); 47 | Assert.Fail(); 48 | } 49 | Assert.Fail(); 50 | } 51 | 52 | [Test] 53 | public void ExceptionReturning() 54 | { 55 | bool success = true; 56 | 57 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 58 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 59 | 60 | DivArgs divArgs = new DivArgs(); 61 | divArgs.x = 10; 62 | divArgs.y = 0; 63 | 64 | IWorkItemResult wir = 65 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs); 66 | 67 | Exception e = null; 68 | try 69 | { 70 | wir.GetResult(out e); 71 | } 72 | catch (Exception ex) 73 | { 74 | ex.GetHashCode(); 75 | success = false; 76 | } 77 | 78 | Assert.IsTrue(success); 79 | Assert.IsTrue(e is DivideByZeroException); 80 | } 81 | 82 | private object DoDiv(object state) 83 | { 84 | DivArgs divArgs = (DivArgs)state; 85 | return (divArgs.x / divArgs.y); 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /STPTests/TestWIGFuncT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amib.Threading; 3 | using NUnit.Framework; 4 | 5 | namespace WorkItemsGroupTests 6 | { 7 | [TestFixture] 8 | [Category("TestWIGFuncT")] 9 | public class TestWIGFuncT 10 | { 11 | private SmartThreadPool _stp; 12 | private IWorkItemsGroup _wig; 13 | 14 | [SetUp] 15 | public void Init() 16 | { 17 | _stp = new SmartThreadPool(); 18 | _wig = _stp.CreateWorkItemsGroup(10); 19 | } 20 | 21 | [TearDown] 22 | public void Fini() 23 | { 24 | _stp.Shutdown(); 25 | } 26 | 27 | [Test] 28 | public void FuncT0() 29 | { 30 | IWorkItemResult wir = _wig.QueueWorkItem(new Func(MaxInt)); 31 | 32 | int result = wir.GetResult(); 33 | 34 | Assert.AreEqual(result, int.MaxValue); 35 | } 36 | 37 | [Test] 38 | public void FuncT1() 39 | { 40 | IWorkItemResult wir = _wig.QueueWorkItem(new Func(Not), true); 41 | 42 | bool result = wir.Result; 43 | 44 | Assert.AreEqual(result, false); 45 | } 46 | 47 | [Test] 48 | public void FuncT2() 49 | { 50 | IWorkItemResult wir = _wig.QueueWorkItem(new Func(string.Concat), "ABC", "xyz"); 51 | 52 | string result = wir.Result; 53 | 54 | Assert.AreEqual(result, "ABCxyz"); 55 | } 56 | 57 | [Test] 58 | public void FuncT3() 59 | { 60 | IWorkItemResult wir = _wig.QueueWorkItem(new Func(Substring), "ABCDEF", 1, 2); 61 | 62 | string result = wir.Result; 63 | 64 | Assert.AreEqual(result, "BC"); 65 | } 66 | 67 | [Test] 68 | public void FuncT4() 69 | { 70 | int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 71 | 72 | IWorkItemResult wir = _wig.QueueWorkItem(new Func(Subarray), numbers, 1, 2, 3); 73 | 74 | int[] result = wir.Result; 75 | 76 | Assert.AreEqual(result, new int[] { 2, 3, 2, 3, 2, 3, }); 77 | } 78 | 79 | private int MaxInt() 80 | { 81 | return int.MaxValue; 82 | } 83 | 84 | private bool Not(bool flag) 85 | { 86 | return !flag; 87 | } 88 | 89 | private string Substring(string s, int startIndex, int length) 90 | { 91 | return s.Substring(startIndex, length); 92 | } 93 | 94 | private int[] Subarray(int[] numbers, int startIndex, int length, int repeat) 95 | { 96 | int[] result = new int[length * repeat]; 97 | for (int i = 0; i < repeat; i++) 98 | { 99 | for (int j = 0; j < length; j++) 100 | { 101 | result[i * length + j] = numbers[startIndex + j]; 102 | } 103 | } 104 | 105 | return result; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /STPTests/TestWIGGetResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace WorkItemsGroupTests 9 | { 10 | /// 11 | /// Summary description for GetResultExample. 12 | /// 13 | [TestFixture] 14 | [Category("Test WorkItemsGroup GetResult")] 15 | public class TestGetResult 16 | { 17 | /// 18 | /// Example of how to queue a work item and then wait infinitely for the result. 19 | /// 20 | [Test] 21 | public void BlockingCall() 22 | { 23 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 24 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 25 | 26 | bool success = false; 27 | 28 | IWorkItemResult wir = 29 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 30 | 31 | if (!wir.IsCompleted) 32 | { 33 | int result = (int)wir.GetResult(); 34 | success = (1 == result); 35 | } 36 | 37 | smartThreadPool.Shutdown(); 38 | 39 | Assert.IsTrue(success); 40 | } 41 | 42 | /// 43 | /// Example of how to queue a work item and then wait on a timeout for the result. 44 | /// 45 | [Test] 46 | public void Timeout() 47 | { 48 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 49 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 50 | 51 | bool success = false; 52 | 53 | IWorkItemResult wir = 54 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 55 | 56 | try 57 | { 58 | wir.GetResult(500, true); 59 | } 60 | catch (WorkItemTimeoutException) 61 | { 62 | success = true; 63 | } 64 | 65 | smartThreadPool.Shutdown(); 66 | 67 | Assert.IsTrue(success); 68 | } 69 | 70 | /// 71 | /// Example of how to interrupt the waiting for a work item to complete. 72 | /// 73 | [Test] 74 | public void WorkItemWaitCanceling() 75 | { 76 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 77 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 78 | 79 | ManualResetEvent cancelWaitHandle = new ManualResetEvent(false); 80 | 81 | bool success = false; 82 | 83 | // Queue a work item that will occupy the thread in the pool 84 | IWorkItemResult wir1 = 85 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 86 | 87 | // Queue another work item that will wait for the first to complete 88 | IWorkItemResult wir2 = 89 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle); 90 | 91 | try 92 | { 93 | wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle); 94 | } 95 | catch (WorkItemTimeoutException) 96 | { 97 | success = true; 98 | } 99 | 100 | smartThreadPool.Shutdown(); 101 | 102 | Assert.IsTrue(success); 103 | } 104 | 105 | private object DoSomeWork(object state) 106 | { 107 | Thread.Sleep(1000); 108 | return 1; 109 | } 110 | 111 | private object SignalCancel(object state) 112 | { 113 | ManualResetEvent cancelWaitHandle = state as ManualResetEvent; 114 | Thread.Sleep(250); 115 | cancelWaitHandle.Set(); 116 | return null; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /STPTests/TestWIGQueueWorkItem.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | using Amib.Threading; 4 | using SmartThreadPoolTests; 5 | 6 | namespace WorkItemsGroupTests 7 | { 8 | /// 9 | /// Tests for QueueWorkItem. 10 | /// 11 | [TestFixture] 12 | [Category("TestQueueWorkItem")] 13 | public class TestQueueWorkItem 14 | { 15 | private SmartThreadPool _stp; 16 | private IWorkItemsGroup _wig; 17 | 18 | [SetUp] 19 | public void Init() 20 | { 21 | _stp = new SmartThreadPool(); 22 | _wig = _stp.CreateWorkItemsGroup(SmartThreadPool.DefaultMaxWorkerThreads); 23 | } 24 | 25 | [TearDown] 26 | public void Fini() 27 | { 28 | _stp.Shutdown(); 29 | } 30 | 31 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback); 32 | [Test] 33 | public void TestQueueWorkItemCall() 34 | { 35 | QueueWorkItemHelper.TestQueueWorkItemCall(_wig); 36 | } 37 | 38 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); 39 | [Test] 40 | public void TestQueueWorkItemCallPrio() 41 | { 42 | QueueWorkItemHelper.TestQueueWorkItemCallPrio(_wig); 43 | } 44 | 45 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); 46 | [Test] 47 | public void TestQueueWorkItemCallStat() 48 | { 49 | QueueWorkItemHelper.TestQueueWorkItemCallStat(_wig); 50 | } 51 | 52 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); 53 | [Test] 54 | public void TestQueueWorkItemCallStatPrio() 55 | { 56 | QueueWorkItemHelper.TestQueueWorkItemCallStatPrio(_wig); 57 | } 58 | 59 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); 60 | [Test] 61 | public void TestQueueWorkItemCallStatPost() 62 | { 63 | QueueWorkItemHelper.TestQueueWorkItemCallStatPost(_wig); 64 | } 65 | 66 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); 67 | [Test] 68 | public void TestQueueWorkItemCallStatPostPrio() 69 | { 70 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPrio(_wig); 71 | } 72 | 73 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); 74 | [Test] 75 | public void TestQueueWorkItemCallStatPostPflg() 76 | { 77 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflg(_wig); 78 | } 79 | 80 | //IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); 81 | [Test] 82 | public void TestQueueWorkItemCallStatPostPflgPrio() 83 | { 84 | QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflgPrio(_wig); 85 | } 86 | 87 | //IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); 88 | [Test] 89 | public void TestQueueWorkItemInfoCall() 90 | { 91 | QueueWorkItemHelper.TestQueueWorkItemInfoCall(_wig); 92 | } 93 | 94 | //IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); 95 | [Test] 96 | public void TestQueueWorkItemInfoCallStat() 97 | { 98 | QueueWorkItemHelper.TestQueueWorkItemInfoCallStat(_wig); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /STPTests/TestWIGStateDispose.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using NUnit.Framework; 5 | 6 | using Amib.Threading; 7 | 8 | namespace WorkItemsGroupTests 9 | { 10 | public class CallerState 11 | { 12 | public int Value { get; private set; } 13 | 14 | protected void IncValue() 15 | { 16 | ++Value; 17 | } 18 | } 19 | 20 | public class NonDisposableCallerState : CallerState 21 | { 22 | public NonDisposableCallerState() 23 | { 24 | IncValue(); 25 | } 26 | } 27 | 28 | public class DisposableCallerState : CallerState, IDisposable 29 | { 30 | public DisposableCallerState() 31 | { 32 | IncValue(); 33 | } 34 | 35 | #region IDisposable Members 36 | 37 | public void Dispose() 38 | { 39 | IncValue(); 40 | } 41 | 42 | #endregion 43 | } 44 | 45 | 46 | /// 47 | /// Summary description for StateDisposeExample. 48 | /// 49 | [TestFixture] 50 | [Category("WorkItemsGroup")] 51 | public class TestStateDispose 52 | { 53 | /// 54 | /// Example of non disposable caller state 55 | /// 56 | [Test] 57 | public void DisposeCallerState() 58 | { 59 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 60 | 61 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 62 | wigStartInfo.DisposeOfStateObjects = true; 63 | 64 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue, wigStartInfo); 65 | 66 | CallerState nonDisposableCallerState = new NonDisposableCallerState(); 67 | CallerState disposableCallerState = new DisposableCallerState(); 68 | 69 | IWorkItemResult wir1 = 70 | workItemsGroup.QueueWorkItem( 71 | new WorkItemCallback(this.DoSomeWork), 72 | nonDisposableCallerState); 73 | 74 | IWorkItemResult wir2 = 75 | workItemsGroup.QueueWorkItem( 76 | new WorkItemCallback(this.DoSomeWork), 77 | disposableCallerState); 78 | 79 | wir1.GetResult(); 80 | Assert.AreEqual(1, nonDisposableCallerState.Value); 81 | 82 | wir2.GetResult(); 83 | 84 | // Wait a little bit for the working thread to call dispose on the 85 | // work item's state. 86 | workItemsGroup.WaitForIdle(); 87 | 88 | Assert.AreEqual(2, disposableCallerState.Value); 89 | 90 | smartThreadPool.Shutdown(); 91 | } 92 | 93 | /// 94 | /// Example of non disposable caller state 95 | /// 96 | [Test] 97 | public void DontDisposeCallerState() 98 | { 99 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 100 | 101 | WIGStartInfo wigStartInfo = new WIGStartInfo(); 102 | wigStartInfo.DisposeOfStateObjects = false; 103 | 104 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue, wigStartInfo); 105 | 106 | CallerState nonDisposableCallerState = new NonDisposableCallerState(); 107 | CallerState disposableCallerState = new DisposableCallerState(); 108 | 109 | IWorkItemResult wir1 = 110 | workItemsGroup.QueueWorkItem( 111 | new WorkItemCallback(this.DoSomeWork), 112 | nonDisposableCallerState); 113 | 114 | IWorkItemResult wir2 = 115 | workItemsGroup.QueueWorkItem( 116 | new WorkItemCallback(this.DoSomeWork), 117 | disposableCallerState); 118 | 119 | wir1.GetResult(); 120 | bool success = (1 == nonDisposableCallerState.Value); 121 | 122 | wir2.GetResult(); 123 | 124 | success = success && (1 == disposableCallerState.Value); 125 | 126 | smartThreadPool.Shutdown(); 127 | 128 | Assert.IsTrue(success); 129 | } 130 | 131 | private object DoSomeWork(object state) 132 | { 133 | Thread.Sleep(1000); 134 | return 1; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /STPTests/TestWIGWaitForIdle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace WorkItemsGroupTests 8 | { 9 | /// 10 | /// Summary description for TestWaitForIdle. 11 | /// 12 | [TestFixture] 13 | [Category("WorkItemsGroup")] 14 | public class TestWaitForIdle 15 | { 16 | /// 17 | /// Example of waiting for idle 18 | /// 19 | [Test] 20 | public void WaitForIdle() 21 | { 22 | SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0); 23 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 24 | 25 | ManualResetEvent isRunning = new ManualResetEvent(false); 26 | 27 | for (int i = 0; i < 4; ++i) 28 | { 29 | workItemsGroup.QueueWorkItem(delegate { isRunning.WaitOne(); }); 30 | } 31 | 32 | bool success = !workItemsGroup.WaitForIdle(1000); 33 | 34 | isRunning.Set(); 35 | 36 | success = success && workItemsGroup.WaitForIdle(1000); 37 | 38 | smartThreadPool.Shutdown(); 39 | 40 | Assert.IsTrue(success); 41 | } 42 | 43 | [Test] 44 | public void WaitForIdleOnSTPThread() 45 | { 46 | SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0); 47 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 48 | 49 | IWorkItemResult wir = workItemsGroup.QueueWorkItem( 50 | new WorkItemCallback(this.DoWaitForIdle), 51 | workItemsGroup); 52 | 53 | Exception e; 54 | wir.GetResult(out e); 55 | 56 | smartThreadPool.Shutdown(); 57 | 58 | Assert.IsNotNull(e); 59 | } 60 | 61 | [Test] 62 | public void WaitForIdleOnSTPThreadForAnotherWorkItemsGroup() 63 | { 64 | SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0); 65 | IWorkItemsGroup workItemsGroup1 = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 66 | IWorkItemsGroup workItemsGroup2 = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 67 | 68 | workItemsGroup1.QueueWorkItem( 69 | new WorkItemCallback(this.DoSomeWork), 70 | 1000); 71 | 72 | workItemsGroup1.QueueWorkItem( 73 | new WorkItemCallback(this.DoSomeWork), 74 | 1000); 75 | 76 | IWorkItemResult wir = workItemsGroup2.QueueWorkItem( 77 | new WorkItemCallback(this.DoWaitForIdle), 78 | workItemsGroup1); 79 | 80 | Exception e; 81 | wir.GetResult(out e); 82 | 83 | smartThreadPool.Shutdown(); 84 | 85 | Assert.IsNull(e); 86 | } 87 | 88 | 89 | private int _x = 0; 90 | private object DoSomeWork(object state) 91 | { 92 | int sleepTime = (int)state; 93 | int newX = Interlocked.Increment(ref _x); 94 | Console.WriteLine("{0}: Enter, newX = {1}", DateTime.Now.ToLongTimeString(), newX); 95 | Console.WriteLine("{0}: Sleeping for {1} ms", DateTime.Now.ToLongTimeString(), sleepTime); 96 | Thread.Sleep(sleepTime); 97 | newX = Interlocked.Increment(ref _x); 98 | Console.WriteLine("{0}: Leave, newX = {1}", DateTime.Now.ToLongTimeString(), newX); 99 | return 1; 100 | } 101 | 102 | private object DoWaitForIdle(object state) 103 | { 104 | IWorkItemsGroup workItemsGroup = state as IWorkItemsGroup; 105 | workItemsGroup.WaitForIdle(); 106 | return null; 107 | } 108 | 109 | 110 | [Test] 111 | public void WaitForIdleWithCancel() 112 | { 113 | SmartThreadPool smartThreadPool = new SmartThreadPool(10 * 1000, 1, 1); 114 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(2); 115 | 116 | _x = 0; 117 | 118 | IWorkItemResult wir1 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000); 119 | IWorkItemResult wir2 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000); 120 | IWorkItemResult wir3 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000); 121 | 122 | while (0 == _x) 123 | { 124 | Thread.Sleep(10); 125 | } 126 | 127 | Console.WriteLine("{0}: Cancelling WIG", DateTime.Now.ToLongTimeString()); 128 | workItemsGroup.Cancel(); 129 | 130 | // At this point: 131 | // The first work item is running 132 | // The second work item is cancelled, but waits in the STP queue 133 | // The third work item is cancelled. 134 | 135 | Assert.AreEqual(1, _x); 136 | 137 | Assert.IsTrue(wir2.IsCanceled); 138 | 139 | Assert.IsTrue(wir3.IsCanceled); 140 | 141 | // Make sure the workItemsGroup is still idle 142 | Assert.IsFalse(workItemsGroup.IsIdle); 143 | 144 | Console.WriteLine("{0}: Waiting for 1st result", DateTime.Now.ToLongTimeString()); 145 | wir1.GetResult(); 146 | 147 | Assert.AreEqual(2, _x); 148 | 149 | bool isIdle = workItemsGroup.WaitForIdle(100); 150 | 151 | Assert.IsTrue(isIdle); 152 | 153 | smartThreadPool.Shutdown(); 154 | } 155 | 156 | [Test] 157 | public void WaitForIdleEvent() 158 | { 159 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 160 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(1); 161 | ManualResetEvent wigIsIdle = new ManualResetEvent(false); 162 | 163 | workItemsGroup.OnIdle += wig => wigIsIdle.Set(); 164 | 165 | workItemsGroup.QueueWorkItem(() => { }); 166 | 167 | bool eventFired = wigIsIdle.WaitOne(100, true); 168 | 169 | smartThreadPool.Shutdown(); 170 | 171 | Assert.IsTrue(eventFired); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /STPTests/TestWaitForIdle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Diagnostics; 4 | 5 | using NUnit.Framework; 6 | 7 | using Amib.Threading; 8 | 9 | namespace SmartThreadPoolTests 10 | { 11 | /// 12 | /// Summary description for TestWaitForIdle. 13 | /// 14 | [TestFixture] 15 | [Category("TestWaitForIdle")] 16 | public class TestWaitForIdle 17 | { 18 | /// 19 | /// Example of waiting for idle 20 | /// 21 | [Test] 22 | public void WaitForIdle() 23 | { 24 | SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0); 25 | 26 | ManualResetEvent isRunning = new ManualResetEvent(false); 27 | 28 | for(int i = 0; i < 4; ++i) 29 | { 30 | smartThreadPool.QueueWorkItem(delegate { isRunning.WaitOne(); }); 31 | } 32 | 33 | bool success = !smartThreadPool.WaitForIdle(1000); 34 | 35 | isRunning.Set(); 36 | 37 | success = success && smartThreadPool.WaitForIdle(1000); 38 | 39 | smartThreadPool.Shutdown(); 40 | 41 | Assert.IsTrue(success); 42 | } 43 | 44 | [Test] 45 | public void WaitForIdleOnWrongThread() 46 | { 47 | SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0); 48 | 49 | IWorkItemResult wir = smartThreadPool.QueueWorkItem( 50 | new WorkItemCallback(this.DoWaitForIdle), 51 | smartThreadPool); 52 | 53 | Exception e; 54 | wir.GetResult(out e); 55 | 56 | smartThreadPool.Shutdown(); 57 | 58 | Assert.IsTrue(e is NotSupportedException); 59 | } 60 | 61 | 62 | private int x = 0; 63 | private object DoSomeWork(object state) 64 | { 65 | Debug.WriteLine(Interlocked.Increment(ref x)); 66 | Thread.Sleep(1000); 67 | return 1; 68 | } 69 | 70 | private object DoWaitForIdle(object state) 71 | { 72 | SmartThreadPool smartThreadPool = state as SmartThreadPool; 73 | smartThreadPool.WaitForIdle(); 74 | return null; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /STPTests/TestWorkItemTimeout.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace SmartThreadPoolTests 8 | { 9 | [TestFixture] 10 | [Category("TestWorkItemTimeout")] 11 | public class TestWorkItemTimeout 12 | { 13 | /// 14 | /// 1. Create STP in suspended mode 15 | /// 2. Queue work item into the STP 16 | /// 3. Wait for the work item to expire 17 | /// 4. Work item's GetResult should throw WorkItemCancelException 18 | /// 19 | [Test] 20 | public void CancelInQueueWorkItem() 21 | { 22 | Assert.Throws(() => 23 | { 24 | STPStartInfo stpStartInfo = new STPStartInfo(); 25 | stpStartInfo.StartSuspended = true; 26 | 27 | bool hasRun = false; 28 | 29 | SmartThreadPool stp = new SmartThreadPool(stpStartInfo); 30 | IWorkItemResult wir = stp.QueueWorkItem( 31 | new WorkItemInfo() {Timeout = 500}, 32 | state => 33 | { 34 | hasRun = true; 35 | return null; 36 | }); 37 | 38 | Assert.IsFalse(wir.IsCanceled); 39 | 40 | Thread.Sleep(2000); 41 | 42 | Assert.IsTrue(wir.IsCanceled); 43 | 44 | stp.Start(); 45 | stp.WaitForIdle(); 46 | 47 | Assert.IsFalse(hasRun); 48 | 49 | try 50 | { 51 | wir.GetResult(); 52 | } 53 | finally 54 | { 55 | stp.Shutdown(); 56 | } 57 | }); 58 | } 59 | 60 | /// 61 | /// 1. Create STP 62 | /// 2. Queue work item that takes some time 63 | /// 3. Wait for it to start 64 | /// 4. The work item timeout expires 65 | /// 5. Make sure, in the work item, that SmartThreadPool.IsWorkItemCanceled is true 66 | /// 5. Wait for the STP to get idle 67 | /// 6. Work item's GetResult should throw WorkItemCancelException 68 | /// 69 | [Test] 70 | public void TimeoutInProgressWorkItemWithSample() 71 | { 72 | bool timedout = false; 73 | ManualResetEvent waitToStart = new ManualResetEvent(false); 74 | ManualResetEvent waitToComplete = new ManualResetEvent(false); 75 | 76 | SmartThreadPool stp = new SmartThreadPool(); 77 | IWorkItemResult wir = stp.QueueWorkItem( 78 | new WorkItemInfo() { Timeout = 500 }, 79 | state => 80 | { 81 | waitToStart.Set(); 82 | Thread.Sleep(1000); 83 | timedout = SmartThreadPool.IsWorkItemCanceled; 84 | waitToComplete.Set(); 85 | return null; 86 | }); 87 | 88 | waitToStart.WaitOne(); 89 | 90 | waitToComplete.WaitOne(); 91 | 92 | Assert.IsTrue(timedout); 93 | 94 | stp.Shutdown(); 95 | } 96 | 97 | /// 98 | /// 1. Create STP 99 | /// 2. Queue work item into the STP 100 | /// 3. Wait for the STP to get idle 101 | /// 4. Work item's GetResult should return value 102 | /// 4. The work item expires 103 | /// 5. Work item's GetResult should return value 104 | /// 105 | [Test] 106 | public void TimeoutCompletedWorkItem() 107 | { 108 | SmartThreadPool stp = new SmartThreadPool(); 109 | IWorkItemResult wir = 110 | stp.QueueWorkItem( 111 | new WorkItemInfo() { Timeout = 500 }, 112 | state => 1); 113 | 114 | stp.WaitForIdle(); 115 | 116 | Assert.AreEqual(wir.GetResult(), 1); 117 | 118 | Thread.Sleep(1000); 119 | 120 | Assert.AreEqual(wir.GetResult(), 1); 121 | 122 | stp.Shutdown(); 123 | } 124 | 125 | /// 126 | /// 1. Create STP 127 | /// 2. Queue work item that takes some time 128 | /// 3. Wait for it to start 129 | /// 4. Cancel the work item (soft) 130 | /// 5. Call to AbortOnWorkItemCancel 131 | /// 5. Wait for the STP to get idle 132 | /// 6. Make sure nothing ran in the work item after the AbortOnWorkItemCancel 133 | /// 134 | [Test] 135 | public void TimeoutInProgressWorkItemSoftWithAbortOnWorkItemCancel() 136 | { 137 | bool abortFailed = false; 138 | ManualResetEvent waitToStart = new ManualResetEvent(false); 139 | ManualResetEvent waitToComplete = new ManualResetEvent(false); 140 | 141 | SmartThreadPool stp = new SmartThreadPool(); 142 | IWorkItemResult wir = stp.QueueWorkItem( 143 | new WorkItemInfo() { Timeout = 500 }, 144 | state => 145 | { 146 | waitToStart.Set(); 147 | Thread.Sleep(1000); 148 | SmartThreadPool.AbortOnWorkItemCancel(); 149 | abortFailed = true; 150 | return null; 151 | }); 152 | 153 | waitToStart.WaitOne(); 154 | 155 | stp.WaitForIdle(); 156 | 157 | Assert.IsTrue(wir.IsCanceled); 158 | Assert.IsFalse(abortFailed); 159 | stp.Shutdown(); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /STPTests/TestWorkItemsGroups.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using NUnit.Framework; 4 | 5 | using Amib.Threading; 6 | 7 | namespace WorkItemsGroupTests 8 | { 9 | /// 10 | /// Summary description for TestWorkItemsGroups. 11 | /// 12 | [TestFixture] 13 | [Category("TestWorkItemsGroups")] 14 | public class TestWorkItemsGroups 15 | { 16 | [Test] 17 | public void BlockingCall() 18 | { 19 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 20 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 21 | 22 | bool success = false; 23 | 24 | IWorkItemResult wir = 25 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 26 | 27 | if (!wir.IsCompleted) 28 | { 29 | int result = (int)wir.GetResult(); 30 | success = (1 == result); 31 | } 32 | 33 | smartThreadPool.Shutdown(); 34 | 35 | Assert.IsTrue(success); 36 | } 37 | 38 | 39 | /// 40 | /// Example of how to queue a work item and then wait on a timeout for the result. 41 | /// 42 | [Test] 43 | public void Timeout() 44 | { 45 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 46 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 47 | 48 | bool success = false; 49 | 50 | IWorkItemResult wir = 51 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 52 | 53 | try 54 | { 55 | wir.GetResult(500, true); 56 | } 57 | catch (WorkItemTimeoutException) 58 | { 59 | success = true; 60 | } 61 | 62 | smartThreadPool.Shutdown(); 63 | 64 | Assert.IsTrue(success); 65 | } 66 | 67 | /// 68 | /// Example of how to interrupt the waiting for a work item to complete. 69 | /// 70 | [Test] 71 | public void WorkItemWaitCanceling() 72 | { 73 | SmartThreadPool smartThreadPool = new SmartThreadPool(); 74 | IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue); 75 | 76 | ManualResetEvent cancelWaitHandle = new ManualResetEvent(false); 77 | 78 | bool success = false; 79 | 80 | // Queue a work item that will occupy the thread in the pool 81 | IWorkItemResult wir1 = 82 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null); 83 | 84 | // Queue another work item that will wait for the first to complete 85 | IWorkItemResult wir2 = 86 | workItemsGroup.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle); 87 | 88 | try 89 | { 90 | wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle); 91 | } 92 | catch (WorkItemTimeoutException) 93 | { 94 | success = true; 95 | } 96 | 97 | smartThreadPool.Shutdown(); 98 | 99 | Assert.IsTrue(success); 100 | } 101 | 102 | private object DoSomeWork(object state) 103 | { 104 | Thread.Sleep(1000); 105 | return 1; 106 | } 107 | 108 | private object SignalCancel(object state) 109 | { 110 | ManualResetEvent cancelWaitHandle = state as ManualResetEvent; 111 | Thread.Sleep(250); 112 | cancelWaitHandle.Set(); 113 | return null; 114 | } 115 | 116 | [Test] 117 | public void Concurrency() 118 | { 119 | } 120 | 121 | [Test] 122 | public void WaitForIdle() 123 | { 124 | } 125 | 126 | [Test] 127 | public void OnIdleEvent() 128 | { 129 | } 130 | 131 | [Test] 132 | public void MultipleGroups() 133 | { 134 | } 135 | 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /STPTests/TestWorkItemsQueue.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Amib.Threading.Internal; 3 | 4 | namespace PriorityQueueTests 5 | { 6 | /// 7 | /// Summary description for TestWorkItemsQueue. 8 | /// 9 | [TestFixture] 10 | [Category("TestWorkItemsQueue")] 11 | public class TestWorkItemsQueue 12 | { 13 | [Test] 14 | public void Init() 15 | { 16 | } 17 | 18 | [Test] 19 | public void IdempotenceWaiterEntry() 20 | { 21 | WorkItemsQueue q = new WorkItemsQueue(); 22 | 23 | Assert.AreEqual(0, q.WaitersCount); 24 | 25 | WorkItemsQueue.WaiterEntry we1 = new WorkItemsQueue.WaiterEntry(); 26 | q.PushWaiter(we1); 27 | 28 | Assert.AreEqual(1, q.WaitersCount); 29 | 30 | q.PushWaiter(we1); 31 | 32 | Assert.AreEqual(1, q.WaitersCount); 33 | 34 | WorkItemsQueue.WaiterEntry we2 = new WorkItemsQueue.WaiterEntry(); 35 | q.PushWaiter(we2); 36 | 37 | Assert.AreEqual(2, q.WaitersCount); 38 | 39 | q.PushWaiter(we2); 40 | 41 | Assert.AreEqual(2, q.WaitersCount); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /STPTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /SmartThreadPool/CallerThreadContext.cs: -------------------------------------------------------------------------------- 1 | #if (NETFRAMEWORK) 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Threading; 6 | using System.Reflection; 7 | using System.Web; 8 | using System.Runtime.Remoting.Messaging; 9 | 10 | 11 | namespace Amib.Threading.Internal 12 | { 13 | #region CallerThreadContext class 14 | 15 | /// 16 | /// This class stores the caller call context in order to restore 17 | /// it when the work item is executed in the thread pool environment. 18 | /// 19 | internal class CallerThreadContext 20 | { 21 | #region Prepare reflection information 22 | 23 | // Cached type information. 24 | private static readonly MethodInfo getLogicalCallContextMethodInfo = 25 | typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); 26 | 27 | private static readonly MethodInfo setLogicalCallContextMethodInfo = 28 | typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); 29 | 30 | private static string HttpContextSlotName = GetHttpContextSlotName(); 31 | 32 | private static string GetHttpContextSlotName() 33 | { 34 | FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); 35 | 36 | if (fi != null) 37 | { 38 | return (string) fi.GetValue(null); 39 | } 40 | 41 | return "HttpContext"; 42 | } 43 | 44 | #endregion 45 | 46 | #region Private fields 47 | 48 | private HttpContext _httpContext; 49 | private LogicalCallContext _callContext; 50 | 51 | #endregion 52 | 53 | /// 54 | /// Constructor 55 | /// 56 | private CallerThreadContext() 57 | { 58 | } 59 | 60 | public bool CapturedCallContext 61 | { 62 | get 63 | { 64 | return (null != _callContext); 65 | } 66 | } 67 | 68 | public bool CapturedHttpContext 69 | { 70 | get 71 | { 72 | return (null != _httpContext); 73 | } 74 | } 75 | 76 | /// 77 | /// Captures the current thread context 78 | /// 79 | /// 80 | public static CallerThreadContext Capture( 81 | bool captureCallContext, 82 | bool captureHttpContext) 83 | { 84 | // Remove this check since if the original call didn't have any context, we don't need to capture it here 85 | //Debug.Assert(captureCallContext || captureHttpContext); 86 | 87 | CallerThreadContext callerThreadContext = new CallerThreadContext(); 88 | 89 | // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() 90 | // Capture Call Context 91 | if(captureCallContext && (getLogicalCallContextMethodInfo != null)) 92 | { 93 | callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); 94 | if (callerThreadContext._callContext != null) 95 | { 96 | callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); 97 | } 98 | } 99 | 100 | // Capture httpContext 101 | if (captureHttpContext && (null != HttpContext.Current)) 102 | { 103 | callerThreadContext._httpContext = HttpContext.Current; 104 | } 105 | 106 | return callerThreadContext; 107 | } 108 | 109 | /// 110 | /// Applies the thread context stored earlier 111 | /// 112 | /// 113 | public static void Apply(CallerThreadContext callerThreadContext) 114 | { 115 | if (null == callerThreadContext) 116 | { 117 | throw new ArgumentNullException("callerThreadContext"); 118 | } 119 | 120 | // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() 121 | // Restore call context 122 | if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) 123 | { 124 | setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); 125 | } 126 | 127 | // Restore HttpContext 128 | if (callerThreadContext._httpContext != null) 129 | { 130 | HttpContext.Current = callerThreadContext._httpContext; 131 | //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); 132 | } 133 | } 134 | } 135 | 136 | #endregion 137 | } 138 | #endif 139 | -------------------------------------------------------------------------------- /SmartThreadPool/CanceledWorkItemsGroup.cs: -------------------------------------------------------------------------------- 1 | namespace Amib.Threading.Internal 2 | { 3 | internal class CanceledWorkItemsGroup 4 | { 5 | public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); 6 | 7 | public CanceledWorkItemsGroup() 8 | { 9 | IsCanceled = false; 10 | } 11 | 12 | public bool IsCanceled { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /SmartThreadPool/EventWaitHandleFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace Amib.Threading.Internal 4 | { 5 | /// 6 | /// EventWaitHandleFactory class. 7 | /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. 8 | /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property 9 | /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. 10 | /// Consequently this class creates the needed XxxResetEvent and replaces the handle if 11 | /// it's a WindowsCE OS. 12 | /// 13 | public static class EventWaitHandleFactory 14 | { 15 | /// 16 | /// Create a new AutoResetEvent object 17 | /// 18 | /// Return a new AutoResetEvent object 19 | public static AutoResetEvent CreateAutoResetEvent() 20 | { 21 | AutoResetEvent waitHandle = new AutoResetEvent(false); 22 | 23 | return waitHandle; 24 | } 25 | 26 | /// 27 | /// Create a new ManualResetEvent object 28 | /// 29 | /// Return a new ManualResetEvent object 30 | public static ManualResetEvent CreateManualResetEvent(bool initialState) 31 | { 32 | ManualResetEvent waitHandle = new ManualResetEvent(initialState); 33 | 34 | return waitHandle; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SmartThreadPool/Exceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Amib.Threading 5 | { 6 | #region Exceptions 7 | 8 | /// 9 | /// Represents an exception in case IWorkItemResult.GetResult has been canceled 10 | /// 11 | public sealed partial class WorkItemCancelException : Exception 12 | { 13 | public WorkItemCancelException() 14 | { 15 | } 16 | 17 | public WorkItemCancelException(string message) 18 | : base(message) 19 | { 20 | } 21 | 22 | public WorkItemCancelException(string message, Exception e) 23 | : base(message, e) 24 | { 25 | } 26 | } 27 | 28 | /// 29 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out 30 | /// 31 | public sealed partial class WorkItemTimeoutException : Exception 32 | { 33 | public WorkItemTimeoutException() 34 | { 35 | } 36 | 37 | public WorkItemTimeoutException(string message) 38 | : base(message) 39 | { 40 | } 41 | 42 | public WorkItemTimeoutException(string message, Exception e) 43 | : base(message, e) 44 | { 45 | } 46 | } 47 | 48 | /// 49 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out 50 | /// 51 | public sealed partial class WorkItemResultException : Exception 52 | { 53 | public WorkItemResultException() 54 | { 55 | } 56 | 57 | public WorkItemResultException(string message) 58 | : base(message) 59 | { 60 | } 61 | 62 | public WorkItemResultException(string message, Exception e) 63 | : base(message, e) 64 | { 65 | } 66 | } 67 | 68 | 69 | /// 70 | /// Represents an exception in case the STP queue is full and work item cannot be queued. 71 | /// Relevant when the STP has a queue size limit 72 | /// 73 | public sealed partial class QueueRejectedException : Exception 74 | { 75 | public QueueRejectedException() 76 | { 77 | } 78 | 79 | public QueueRejectedException(string message) 80 | : base(message) 81 | { 82 | } 83 | 84 | public QueueRejectedException(string message, Exception e) 85 | : base(message, e) 86 | { 87 | } 88 | } 89 | 90 | /// 91 | /// Represents an exception in case IWorkItemResult.GetResult has been canceled 92 | /// 93 | [Serializable] 94 | public sealed partial class WorkItemCancelException 95 | { 96 | public WorkItemCancelException(SerializationInfo si, StreamingContext sc) 97 | : base(si, sc) 98 | { 99 | } 100 | } 101 | 102 | /// 103 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out 104 | /// 105 | [Serializable] 106 | public sealed partial class WorkItemTimeoutException 107 | { 108 | public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) 109 | : base(si, sc) 110 | { 111 | } 112 | } 113 | 114 | /// 115 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out 116 | /// 117 | [Serializable] 118 | public sealed partial class WorkItemResultException 119 | { 120 | public WorkItemResultException(SerializationInfo si, StreamingContext sc) 121 | : base(si, sc) 122 | { 123 | } 124 | } 125 | 126 | /// 127 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out 128 | /// 129 | [Serializable] 130 | public sealed partial class QueueRejectedException 131 | { 132 | public QueueRejectedException(SerializationInfo si, StreamingContext sc) 133 | : base(si, sc) 134 | { 135 | } 136 | } 137 | 138 | #endregion 139 | } 140 | -------------------------------------------------------------------------------- /SmartThreadPool/InternalInterfaces.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Amib.Threading.Internal 3 | { 4 | /// 5 | /// An internal delegate to call when the WorkItem starts or completes 6 | /// 7 | internal delegate void WorkItemStateCallback(WorkItem workItem); 8 | 9 | internal interface IInternalWorkItemResult 10 | { 11 | event WorkItemStateCallback OnWorkItemStarted; 12 | event WorkItemStateCallback OnWorkItemCompleted; 13 | } 14 | 15 | internal interface IInternalWaitableResult 16 | { 17 | /// 18 | /// This method is intent for internal use. 19 | /// 20 | IWorkItemResult GetWorkItemResult(); 21 | } 22 | 23 | public interface IHasWorkItemPriority 24 | { 25 | WorkItemPriority WorkItemPriority { get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartThreadPool/PriorityQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | 6 | namespace Amib.Threading.Internal 7 | { 8 | #region PriorityQueue class 9 | 10 | /// 11 | /// PriorityQueue class 12 | /// This class is not thread safe because we use external lock 13 | /// 14 | public sealed class PriorityQueue : IEnumerable 15 | { 16 | #region Private members 17 | 18 | /// 19 | /// The number of queues, there is one for each type of priority 20 | /// 21 | private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; 22 | 23 | /// 24 | /// Work items queues. There is one for each type of priority 25 | /// 26 | private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; 27 | 28 | /// 29 | /// The total number of work items within the queues 30 | /// 31 | private int _workItemsCount; 32 | 33 | /// 34 | /// Use with IEnumerable interface 35 | /// 36 | private int _version; 37 | 38 | #endregion 39 | 40 | #region Contructor 41 | 42 | public PriorityQueue() 43 | { 44 | for(int i = 0; i < _queues.Length; ++i) 45 | { 46 | _queues[i] = new LinkedList(); 47 | } 48 | } 49 | 50 | #endregion 51 | 52 | #region Methods 53 | 54 | /// 55 | /// Enqueue a work item. 56 | /// 57 | /// A work item 58 | public void Enqueue(IHasWorkItemPriority workItem) 59 | { 60 | Debug.Assert(null != workItem); 61 | 62 | int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; 63 | Debug.Assert(queueIndex >= 0); 64 | Debug.Assert(queueIndex < _queuesCount); 65 | 66 | _queues[queueIndex].AddLast(workItem); 67 | ++_workItemsCount; 68 | ++_version; 69 | } 70 | 71 | /// 72 | /// Dequeque a work item. 73 | /// 74 | /// Returns the next work item 75 | public IHasWorkItemPriority Dequeue() 76 | { 77 | IHasWorkItemPriority workItem = null; 78 | 79 | if(_workItemsCount > 0) 80 | { 81 | int queueIndex = GetNextNonEmptyQueue(-1); 82 | Debug.Assert(queueIndex >= 0); 83 | workItem = _queues[queueIndex].First.Value; 84 | _queues[queueIndex].RemoveFirst(); 85 | Debug.Assert(null != workItem); 86 | --_workItemsCount; 87 | ++_version; 88 | } 89 | 90 | return workItem; 91 | } 92 | 93 | /// 94 | /// Find the next non empty queue starting at queue queueIndex+1 95 | /// 96 | /// The index-1 to start from 97 | /// 98 | /// The index of the next non empty queue or -1 if all the queues are empty 99 | /// 100 | private int GetNextNonEmptyQueue(int queueIndex) 101 | { 102 | for(int i = queueIndex+1; i < _queuesCount; ++i) 103 | { 104 | if(_queues[i].Count > 0) 105 | { 106 | return i; 107 | } 108 | } 109 | return -1; 110 | } 111 | 112 | /// 113 | /// The number of work items 114 | /// 115 | public int Count 116 | { 117 | get 118 | { 119 | return _workItemsCount; 120 | } 121 | } 122 | 123 | /// 124 | /// Clear all the work items 125 | /// 126 | public void Clear() 127 | { 128 | if (_workItemsCount > 0) 129 | { 130 | foreach(LinkedList queue in _queues) 131 | { 132 | queue.Clear(); 133 | } 134 | _workItemsCount = 0; 135 | ++_version; 136 | } 137 | } 138 | 139 | #endregion 140 | 141 | #region IEnumerable Members 142 | 143 | /// 144 | /// Returns an enumerator to iterate over the work items 145 | /// 146 | /// Returns an enumerator 147 | public IEnumerator GetEnumerator() 148 | { 149 | return new PriorityQueueEnumerator(this); 150 | } 151 | 152 | #endregion 153 | 154 | #region PriorityQueueEnumerator 155 | 156 | /// 157 | /// The class the implements the enumerator 158 | /// 159 | private class PriorityQueueEnumerator : IEnumerator 160 | { 161 | private readonly PriorityQueue _priorityQueue; 162 | private int _version; 163 | private int _queueIndex; 164 | private IEnumerator _enumerator; 165 | 166 | public PriorityQueueEnumerator(PriorityQueue priorityQueue) 167 | { 168 | _priorityQueue = priorityQueue; 169 | _version = _priorityQueue._version; 170 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 171 | if (_queueIndex >= 0) 172 | { 173 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 174 | } 175 | else 176 | { 177 | _enumerator = null; 178 | } 179 | } 180 | 181 | #region IEnumerator Members 182 | 183 | public void Reset() 184 | { 185 | _version = _priorityQueue._version; 186 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 187 | if (_queueIndex >= 0) 188 | { 189 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 190 | } 191 | else 192 | { 193 | _enumerator = null; 194 | } 195 | } 196 | 197 | public object Current 198 | { 199 | get 200 | { 201 | Debug.Assert(null != _enumerator); 202 | return _enumerator.Current; 203 | } 204 | } 205 | 206 | public bool MoveNext() 207 | { 208 | if (null == _enumerator) 209 | { 210 | return false; 211 | } 212 | 213 | if(_version != _priorityQueue._version) 214 | { 215 | throw new InvalidOperationException("The collection has been modified"); 216 | 217 | } 218 | if (!_enumerator.MoveNext()) 219 | { 220 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); 221 | if(-1 == _queueIndex) 222 | { 223 | return false; 224 | } 225 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 226 | _enumerator.MoveNext(); 227 | return true; 228 | } 229 | return true; 230 | } 231 | 232 | #endregion 233 | } 234 | 235 | #endregion 236 | } 237 | 238 | #endregion 239 | } 240 | -------------------------------------------------------------------------------- /SmartThreadPool/STPEventWaitHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Amib.Threading.Internal 5 | { 6 | internal static class STPEventWaitHandle 7 | { 8 | public const int WaitTimeout = Timeout.Infinite; 9 | 10 | internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) 11 | { 12 | return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); 13 | } 14 | 15 | internal static int WaitAny(WaitHandle[] waitHandles) 16 | { 17 | return WaitHandle.WaitAny(waitHandles); 18 | } 19 | 20 | internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) 21 | { 22 | return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); 23 | } 24 | 25 | internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) 26 | { 27 | return waitHandle.WaitOne(millisecondsTimeout, exitContext); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartThreadPool/SmartThreadPool.ThreadEntry.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using Amib.Threading.Internal; 4 | 5 | namespace Amib.Threading 6 | { 7 | public partial class SmartThreadPool 8 | { 9 | #region ThreadEntry class 10 | 11 | internal class ThreadEntry 12 | { 13 | /// 14 | /// The thread creation time 15 | /// The value is stored as UTC value. 16 | /// 17 | private readonly DateTime _creationTime; 18 | 19 | /// 20 | /// The last time this thread has been running 21 | /// It is updated by IAmAlive() method 22 | /// The value is stored as UTC value. 23 | /// 24 | private DateTime _lastAliveTime; 25 | 26 | /// 27 | /// A reference from each thread in the thread pool to its SmartThreadPool 28 | /// object container. 29 | /// With this variable a thread can know whatever it belongs to a 30 | /// SmartThreadPool. 31 | /// 32 | private readonly SmartThreadPool _associatedSmartThreadPool; 33 | 34 | /// 35 | /// A reference to the current work item a thread from the thread pool 36 | /// is executing. 37 | /// 38 | public WorkItem CurrentWorkItem { get; set; } 39 | 40 | public ThreadEntry(SmartThreadPool stp) 41 | { 42 | _associatedSmartThreadPool = stp; 43 | _creationTime = DateTime.UtcNow; 44 | _lastAliveTime = DateTime.MinValue; 45 | } 46 | 47 | public SmartThreadPool AssociatedSmartThreadPool 48 | { 49 | get { return _associatedSmartThreadPool; } 50 | } 51 | 52 | public void IAmAlive() 53 | { 54 | _lastAliveTime = DateTime.UtcNow; 55 | } 56 | } 57 | 58 | #endregion 59 | } 60 | } -------------------------------------------------------------------------------- /SmartThreadPool/SmartThreadPool.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net40;net45;net46;netstandard2.0;netcoreapp3.0;netcoreapp3.1;net5.0 5 | SmartThreadPool 6 | SmartThreadPool 7 | TRACE; 8 | true 9 | 2.3.0 10 | 11 | Ami Bar 12 | Smart Thread Pool, implemented in .NET 13 | SmartThreadPool Thread Pool .NET 14 | MS-PL 15 | Ami Bar 16 | https://github.com/amibar/SmartThreadPool 17 | https://github.com/amibar/SmartThreadPool 18 | Debug;Release;Publish 19 | Added .net core 3.1 and 5.0 support 20 | SmartThreadPool.dll 21 | 2.3.0.0 22 | 2.3.0.0 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | <_Parameter1>STPTests 40 | 41 | 42 | 43 | 44 | 45 | <_Parameter1>STPTests 46 | 47 | 48 | 49 | 50 | 51 | <_Parameter1>STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad 52 | 53 | 54 | 55 | 56 | true 57 | true 58 | ..\publish\Keys\STP.snk 59 | ..\publish\dist\bin 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SmartThreadPool/Stopwatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Amib.Threading.Internal 4 | { 5 | /// 6 | /// Stopwatch class 7 | /// Used with WindowsCE and Silverlight which don't have Stopwatch 8 | /// 9 | internal class Stopwatch 10 | { 11 | private long _elapsed; 12 | private bool _isRunning; 13 | private long _startTimeStamp; 14 | 15 | public Stopwatch() 16 | { 17 | Reset(); 18 | } 19 | 20 | private long GetElapsedDateTimeTicks() 21 | { 22 | long rawElapsedTicks = GetRawElapsedTicks(); 23 | return rawElapsedTicks; 24 | } 25 | 26 | private long GetRawElapsedTicks() 27 | { 28 | long elapsed = _elapsed; 29 | if (_isRunning) 30 | { 31 | long ticks = GetTimestamp() - _startTimeStamp; 32 | elapsed += ticks; 33 | } 34 | return elapsed; 35 | } 36 | 37 | public static long GetTimestamp() 38 | { 39 | return DateTime.UtcNow.Ticks; 40 | } 41 | 42 | public void Reset() 43 | { 44 | _elapsed = 0L; 45 | _isRunning = false; 46 | _startTimeStamp = 0L; 47 | } 48 | 49 | public void Start() 50 | { 51 | if (!_isRunning) 52 | { 53 | _startTimeStamp = GetTimestamp(); 54 | _isRunning = true; 55 | } 56 | } 57 | 58 | public static Stopwatch StartNew() 59 | { 60 | Stopwatch stopwatch = new Stopwatch(); 61 | stopwatch.Start(); 62 | return stopwatch; 63 | } 64 | 65 | public void Stop() 66 | { 67 | if (_isRunning) 68 | { 69 | long ticks = GetTimestamp() - _startTimeStamp; 70 | _elapsed += ticks; 71 | _isRunning = false; 72 | } 73 | } 74 | 75 | // Properties 76 | public TimeSpan Elapsed 77 | { 78 | get 79 | { 80 | return new TimeSpan(GetElapsedDateTimeTicks()); 81 | } 82 | } 83 | 84 | public long ElapsedMilliseconds 85 | { 86 | get 87 | { 88 | return (GetElapsedDateTimeTicks() / 0x2710L); 89 | } 90 | } 91 | 92 | public long ElapsedTicks 93 | { 94 | get 95 | { 96 | return GetRawElapsedTicks(); 97 | } 98 | } 99 | 100 | public bool IsRunning 101 | { 102 | get 103 | { 104 | return _isRunning; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /SmartThreadPool/SynchronizedDictionary.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Amib.Threading.Internal 4 | { 5 | internal class SynchronizedDictionary 6 | { 7 | private readonly Dictionary _dictionary; 8 | private readonly object _lock; 9 | 10 | public SynchronizedDictionary() 11 | { 12 | _lock = new object(); 13 | _dictionary = new Dictionary(); 14 | } 15 | 16 | public int Count 17 | { 18 | get { return _dictionary.Count; } 19 | } 20 | 21 | public bool Contains(TKey key) 22 | { 23 | lock (_lock) 24 | { 25 | return _dictionary.ContainsKey(key); 26 | } 27 | } 28 | 29 | public void Remove(TKey key) 30 | { 31 | lock (_lock) 32 | { 33 | _dictionary.Remove(key); 34 | } 35 | } 36 | 37 | public object SyncRoot 38 | { 39 | get { return _lock; } 40 | } 41 | 42 | public TValue this[TKey key] 43 | { 44 | get 45 | { 46 | lock (_lock) 47 | { 48 | return _dictionary[key]; 49 | } 50 | } 51 | set 52 | { 53 | lock (_lock) 54 | { 55 | _dictionary[key] = value; 56 | } 57 | } 58 | } 59 | 60 | public Dictionary.KeyCollection Keys 61 | { 62 | get 63 | { 64 | lock (_lock) 65 | { 66 | return _dictionary.Keys; 67 | } 68 | } 69 | } 70 | 71 | public Dictionary.ValueCollection Values 72 | { 73 | get 74 | { 75 | lock (_lock) 76 | { 77 | return _dictionary.Values; 78 | } 79 | } 80 | } 81 | public void Clear() 82 | { 83 | lock (_lock) 84 | { 85 | _dictionary.Clear(); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /SmartThreadPool/WIGStartInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Amib.Threading 4 | { 5 | /// 6 | /// Summary description for WIGStartInfo. 7 | /// 8 | public class WIGStartInfo 9 | { 10 | private bool _useCallerCallContext; 11 | private bool _useCallerHttpContext; 12 | private bool _disposeOfStateObjects; 13 | private CallToPostExecute _callToPostExecute; 14 | private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; 15 | private bool _startSuspended; 16 | private WorkItemPriority _workItemPriority; 17 | private bool _fillStateWithArgs; 18 | 19 | protected bool _readOnly; 20 | 21 | public WIGStartInfo() 22 | { 23 | _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; 24 | _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; 25 | _startSuspended = SmartThreadPool.DefaultStartSuspended; 26 | _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; 27 | _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; 28 | _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; 29 | _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 30 | _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 31 | } 32 | 33 | public WIGStartInfo(WIGStartInfo wigStartInfo) 34 | { 35 | _useCallerCallContext = wigStartInfo.UseCallerCallContext; 36 | _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; 37 | _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 38 | _callToPostExecute = wigStartInfo.CallToPostExecute; 39 | _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; 40 | _workItemPriority = wigStartInfo.WorkItemPriority; 41 | _startSuspended = wigStartInfo.StartSuspended; 42 | _fillStateWithArgs = wigStartInfo.FillStateWithArgs; 43 | } 44 | 45 | protected void ThrowIfReadOnly() 46 | { 47 | if (_readOnly) 48 | { 49 | throw new NotSupportedException("This is a readonly instance and set is not supported"); 50 | } 51 | } 52 | 53 | /// 54 | /// Get/Set if to use the caller's security context 55 | /// 56 | public virtual bool UseCallerCallContext 57 | { 58 | get { return _useCallerCallContext; } 59 | set 60 | { 61 | ThrowIfReadOnly(); 62 | _useCallerCallContext = value; 63 | } 64 | } 65 | 66 | 67 | /// 68 | /// Get/Set if to use the caller's HTTP context 69 | /// 70 | public virtual bool UseCallerHttpContext 71 | { 72 | get { return _useCallerHttpContext; } 73 | set 74 | { 75 | ThrowIfReadOnly(); 76 | _useCallerHttpContext = value; 77 | } 78 | } 79 | 80 | 81 | /// 82 | /// Get/Set if to dispose of the state object of a work item 83 | /// 84 | public virtual bool DisposeOfStateObjects 85 | { 86 | get { return _disposeOfStateObjects; } 87 | set 88 | { 89 | ThrowIfReadOnly(); 90 | _disposeOfStateObjects = value; 91 | } 92 | } 93 | 94 | 95 | /// 96 | /// Get/Set the run the post execute options 97 | /// 98 | public virtual CallToPostExecute CallToPostExecute 99 | { 100 | get { return _callToPostExecute; } 101 | set 102 | { 103 | ThrowIfReadOnly(); 104 | _callToPostExecute = value; 105 | } 106 | } 107 | 108 | 109 | /// 110 | /// Get/Set the default post execute callback 111 | /// 112 | public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback 113 | { 114 | get { return _postExecuteWorkItemCallback; } 115 | set 116 | { 117 | ThrowIfReadOnly(); 118 | _postExecuteWorkItemCallback = value; 119 | } 120 | } 121 | 122 | 123 | /// 124 | /// Get/Set if the work items execution should be suspended until the Start() 125 | /// method is called. 126 | /// 127 | public virtual bool StartSuspended 128 | { 129 | get { return _startSuspended; } 130 | set 131 | { 132 | ThrowIfReadOnly(); 133 | _startSuspended = value; 134 | } 135 | } 136 | 137 | 138 | /// 139 | /// Get/Set the default priority that a work item gets when it is enqueued 140 | /// 141 | public virtual WorkItemPriority WorkItemPriority 142 | { 143 | get { return _workItemPriority; } 144 | set { _workItemPriority = value; } 145 | } 146 | 147 | /// 148 | /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the 149 | /// arguments as an object array into the state of the work item. 150 | /// The arguments can be access later by IWorkItemResult.State. 151 | /// 152 | public virtual bool FillStateWithArgs 153 | { 154 | get { return _fillStateWithArgs; } 155 | set 156 | { 157 | ThrowIfReadOnly(); 158 | _fillStateWithArgs = value; 159 | } 160 | } 161 | 162 | /// 163 | /// Get a readonly version of this WIGStartInfo 164 | /// 165 | /// Returns a readonly reference to this WIGStartInfoRO 166 | public WIGStartInfo AsReadOnly() 167 | { 168 | return new WIGStartInfo(this) { _readOnly = true }; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /SmartThreadPool/WorkItem.WorkItemResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | 6 | namespace Amib.Threading.Internal 7 | { 8 | public partial class WorkItem 9 | { 10 | #region WorkItemResult class 11 | 12 | private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult 13 | { 14 | /// 15 | /// A back reference to the work item 16 | /// 17 | private readonly WorkItem _workItem; 18 | 19 | public WorkItemResult(WorkItem workItem) 20 | { 21 | _workItem = workItem; 22 | } 23 | 24 | internal WorkItem GetWorkItem() 25 | { 26 | return _workItem; 27 | } 28 | 29 | #region IWorkItemResult Members 30 | 31 | public bool IsCompleted 32 | { 33 | get 34 | { 35 | return _workItem.IsCompleted; 36 | } 37 | } 38 | 39 | public bool IsCanceled 40 | { 41 | get 42 | { 43 | return _workItem.IsCanceled; 44 | } 45 | } 46 | 47 | public object GetResult() 48 | { 49 | return _workItem.GetResult(Timeout.Infinite, true, null); 50 | } 51 | 52 | public object GetResult(int millisecondsTimeout, bool exitContext) 53 | { 54 | return _workItem.GetResult(millisecondsTimeout, exitContext, null); 55 | } 56 | 57 | public object GetResult(TimeSpan timeout, bool exitContext) 58 | { 59 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); 60 | } 61 | 62 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) 63 | { 64 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); 65 | } 66 | 67 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) 68 | { 69 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 70 | } 71 | 72 | public object GetResult(out Exception e) 73 | { 74 | return _workItem.GetResult(Timeout.Infinite, true, null, out e); 75 | } 76 | 77 | public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) 78 | { 79 | return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); 80 | } 81 | 82 | public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) 83 | { 84 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); 85 | } 86 | 87 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) 88 | { 89 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); 90 | } 91 | 92 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) 93 | { 94 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); 95 | } 96 | 97 | public bool Cancel() 98 | { 99 | return Cancel(false); 100 | } 101 | 102 | public bool Cancel(bool abortExecution) 103 | { 104 | return _workItem.Cancel(abortExecution); 105 | } 106 | 107 | public object State 108 | { 109 | get 110 | { 111 | return _workItem._state; 112 | } 113 | } 114 | 115 | public WorkItemPriority WorkItemPriority 116 | { 117 | get 118 | { 119 | return _workItem._workItemInfo.WorkItemPriority; 120 | } 121 | } 122 | 123 | /// 124 | /// Return the result, same as GetResult() 125 | /// 126 | public object Result 127 | { 128 | get { return GetResult(); } 129 | } 130 | 131 | /// 132 | /// Returns the exception if occured otherwise returns null. 133 | /// This value is valid only after the work item completed, 134 | /// before that it is always null. 135 | /// 136 | public object Exception 137 | { 138 | get { return _workItem._exception; } 139 | } 140 | 141 | #endregion 142 | 143 | #region IInternalWorkItemResult Members 144 | 145 | public event WorkItemStateCallback OnWorkItemStarted 146 | { 147 | add 148 | { 149 | _workItem.OnWorkItemStarted += value; 150 | } 151 | remove 152 | { 153 | _workItem.OnWorkItemStarted -= value; 154 | } 155 | } 156 | 157 | 158 | public event WorkItemStateCallback OnWorkItemCompleted 159 | { 160 | add 161 | { 162 | _workItem.OnWorkItemCompleted += value; 163 | } 164 | remove 165 | { 166 | _workItem.OnWorkItemCompleted -= value; 167 | } 168 | } 169 | 170 | #endregion 171 | 172 | #region IInternalWorkItemResult Members 173 | 174 | public IWorkItemResult GetWorkItemResult() 175 | { 176 | return this; 177 | } 178 | 179 | public IWorkItemResult GetWorkItemResultT() 180 | { 181 | return new WorkItemResultTWrapper(this); 182 | } 183 | 184 | #endregion 185 | } 186 | 187 | #endregion 188 | 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /SmartThreadPool/WorkItemInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Amib.Threading 2 | { 3 | #region WorkItemInfo class 4 | 5 | /// 6 | /// Summary description for WorkItemInfo. 7 | /// 8 | public class WorkItemInfo 9 | { 10 | public WorkItemInfo() 11 | { 12 | UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 13 | UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 14 | DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; 15 | CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; 16 | PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; 17 | WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; 18 | } 19 | 20 | public WorkItemInfo(WorkItemInfo workItemInfo) 21 | { 22 | UseCallerCallContext = workItemInfo.UseCallerCallContext; 23 | UseCallerHttpContext = workItemInfo.UseCallerHttpContext; 24 | DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; 25 | CallToPostExecute = workItemInfo.CallToPostExecute; 26 | PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; 27 | WorkItemPriority = workItemInfo.WorkItemPriority; 28 | Timeout = workItemInfo.Timeout; 29 | } 30 | 31 | /// 32 | /// Get/Set if to use the caller's security context 33 | /// 34 | public bool UseCallerCallContext { get; set; } 35 | 36 | /// 37 | /// Get/Set if to use the caller's HTTP context 38 | /// 39 | public bool UseCallerHttpContext { get; set; } 40 | 41 | /// 42 | /// Get/Set if to dispose of the state object of a work item 43 | /// 44 | public bool DisposeOfStateObjects { get; set; } 45 | 46 | /// 47 | /// Get/Set the run the post execute options 48 | /// 49 | public CallToPostExecute CallToPostExecute { get; set; } 50 | 51 | /// 52 | /// Get/Set the post execute callback 53 | /// 54 | public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } 55 | 56 | /// 57 | /// Get/Set the work item's priority 58 | /// 59 | public WorkItemPriority WorkItemPriority { get; set; } 60 | 61 | /// 62 | /// Get/Set the work item's timout in milliseconds. 63 | /// This is a passive timout. When the timout expires the work item won't be actively aborted! 64 | /// 65 | public long Timeout { get; set; } 66 | } 67 | 68 | #endregion 69 | } 70 | -------------------------------------------------------------------------------- /SmartThreadPool/WorkItemResultTWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Amib.Threading.Internal 5 | { 6 | #region WorkItemResultTWrapper class 7 | 8 | internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult 9 | { 10 | private readonly IWorkItemResult _workItemResult; 11 | 12 | public WorkItemResultTWrapper(IWorkItemResult workItemResult) 13 | { 14 | _workItemResult = workItemResult; 15 | } 16 | 17 | #region IWorkItemResult Members 18 | 19 | public TResult GetResult() 20 | { 21 | return (TResult)_workItemResult.GetResult(); 22 | } 23 | 24 | public TResult GetResult(int millisecondsTimeout, bool exitContext) 25 | { 26 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); 27 | } 28 | 29 | public TResult GetResult(TimeSpan timeout, bool exitContext) 30 | { 31 | return (TResult)_workItemResult.GetResult(timeout, exitContext); 32 | } 33 | 34 | public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) 35 | { 36 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); 37 | } 38 | 39 | public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) 40 | { 41 | return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); 42 | } 43 | 44 | public TResult GetResult(out Exception e) 45 | { 46 | return (TResult)_workItemResult.GetResult(out e); 47 | } 48 | 49 | public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) 50 | { 51 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); 52 | } 53 | 54 | public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) 55 | { 56 | return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); 57 | } 58 | 59 | public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) 60 | { 61 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); 62 | } 63 | 64 | public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) 65 | { 66 | return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); 67 | } 68 | 69 | public bool IsCompleted 70 | { 71 | get { return _workItemResult.IsCompleted; } 72 | } 73 | 74 | public bool IsCanceled 75 | { 76 | get { return _workItemResult.IsCanceled; } 77 | } 78 | 79 | public object State 80 | { 81 | get { return _workItemResult.State; } 82 | } 83 | 84 | public bool Cancel() 85 | { 86 | return _workItemResult.Cancel(); 87 | } 88 | 89 | public bool Cancel(bool abortExecution) 90 | { 91 | return _workItemResult.Cancel(abortExecution); 92 | } 93 | 94 | public WorkItemPriority WorkItemPriority 95 | { 96 | get { return _workItemResult.WorkItemPriority; } 97 | } 98 | 99 | public TResult Result 100 | { 101 | get { return (TResult)_workItemResult.Result; } 102 | } 103 | 104 | public object Exception 105 | { 106 | get { return _workItemResult.Exception; } 107 | } 108 | 109 | #region IInternalWorkItemResult Members 110 | 111 | public IWorkItemResult GetWorkItemResult() 112 | { 113 | return _workItemResult.GetWorkItemResult(); 114 | } 115 | 116 | public IWorkItemResult GetWorkItemResultT() 117 | { 118 | return (IWorkItemResult)this; 119 | } 120 | 121 | #endregion 122 | 123 | #endregion 124 | } 125 | 126 | #endregion 127 | 128 | } 129 | -------------------------------------------------------------------------------- /TestSmartThreadPool/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amibar/SmartThreadPool/27cb713535138416fb82431cefcbe89d6d3c1114/TestSmartThreadPool/App.ico -------------------------------------------------------------------------------- /TestSmartThreadPool/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("")] 4 | [assembly: AssemblyDescription("")] 5 | [assembly: AssemblyConfiguration("")] 6 | [assembly: AssemblyCompany("")] 7 | [assembly: AssemblyProduct("")] 8 | [assembly: AssemblyCopyright("")] 9 | [assembly: AssemblyTrademark("")] 10 | [assembly: AssemblyCulture("")] 11 | [assembly: AssemblyVersion("1.0.*")] 12 | [assembly: AssemblyDelaySign(false)] 13 | [assembly: AssemblyKeyFile("")] 14 | [assembly: AssemblyKeyName("")] 15 | -------------------------------------------------------------------------------- /TestSmartThreadPool/TestSmartThreadPool.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Local 5 | 9.0.30729 6 | 2.0 7 | {976DB12F-9198-4AD9-981A-1652615C9B0D} 8 | Debug 9 | AnyCPU 10 | App.ico 11 | 12 | 13 | TestSmartThreadPool 14 | 15 | 16 | JScript 17 | Grid 18 | IE50 19 | false 20 | WinExe 21 | TestSmartThreadPool 22 | OnBuildSuccess 23 | TestSmartThreadPool.Form1 24 | 25 | 26 | 27 | 28 | 3.5 29 | v4.6 30 | 31 | 32 | 33 | bin\Windows\Debug\ 34 | false 35 | 285212672 36 | false 37 | 38 | 39 | TRACE;DEBUG;_WINDOWS 40 | 41 | 42 | true 43 | 4096 44 | false 45 | 46 | 47 | false 48 | false 49 | false 50 | false 51 | 4 52 | full 53 | prompt 54 | false 55 | 56 | 57 | bin\Windows\Release\ 58 | false 59 | 285212672 60 | false 61 | 62 | 63 | TRACE;_WINDOWS 64 | 65 | 66 | false 67 | 4096 68 | false 69 | 70 | 71 | true 72 | false 73 | false 74 | false 75 | 4 76 | none 77 | prompt 78 | false 79 | 80 | 81 | ..\publish\dist\demos\Windows\TestSmartThreadPool\ 82 | TRACE;_WINDOWS 83 | 285212672 84 | true 85 | 4096 86 | AnyCPU 87 | prompt 88 | false 89 | false 90 | 91 | 92 | 93 | System 94 | 95 | 96 | System.Data 97 | 98 | 99 | System.Drawing 100 | 101 | 102 | System.Windows.Forms 103 | 104 | 105 | System.XML 106 | 107 | 108 | {52f1074c-33af-4cbc-885b-dff14a4b4442} 109 | SmartThreadPool 110 | 111 | 112 | UsageControl 113 | {C11A4561-CCB5-4C96-8DF2-B804031D89D8} 114 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 115 | 116 | 117 | 118 | 119 | 120 | Code 121 | 122 | 123 | Form 124 | 125 | 126 | Form1.cs 127 | Designer 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /TestSmartThreadPool/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UsageControl/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("")] 4 | [assembly: AssemblyDescription("")] 5 | [assembly: AssemblyConfiguration("")] 6 | [assembly: AssemblyCompany("")] 7 | [assembly: AssemblyProduct("")] 8 | [assembly: AssemblyCopyright("")] 9 | [assembly: AssemblyTrademark("")] 10 | [assembly: AssemblyCulture("")] 11 | [assembly: AssemblyVersion("1.0.*")] 12 | [assembly: AssemblyDelaySign(false)] 13 | [assembly: AssemblyKeyFile("")] 14 | [assembly: AssemblyKeyName("")] 15 | -------------------------------------------------------------------------------- /UsageControl/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace UsageControl.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UsageControl.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /UsageControl/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /UsageControl/QueueUsageControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace UsageControl 2 | { 3 | partial class QueueUsageControl 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.timer1 = new System.Windows.Forms.Timer(this.components); 33 | this.SuspendLayout(); 34 | // 35 | // timer1 36 | // 37 | this.timer1.Enabled = true; 38 | this.timer1.Interval = 500; 39 | this.timer1.Tick += new System.EventHandler(this.timer1_Tick); 40 | // 41 | // QueueUsageControl 42 | // 43 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 44 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 45 | this.BackColor = System.Drawing.Color.Transparent; 46 | this.Name = "QueueUsageControl"; 47 | this.Size = new System.Drawing.Size(167, 247); 48 | this.Resize += new System.EventHandler(this.QueueUsageControl_Resize); 49 | this.ResumeLayout(false); 50 | 51 | } 52 | 53 | #endregion 54 | 55 | private System.Windows.Forms.Timer timer1; 56 | 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /UsageControl/QueueUsageControl.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /UsageControl/QueueUsageEntry.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace UsageControl 4 | { 5 | public partial class QueueUsageControl 6 | { 7 | public class QueueUsageEntry 8 | { 9 | public QueueUsageEntry( 10 | string text, 11 | Color color) : this (text, color, false) 12 | { 13 | } 14 | 15 | public QueueUsageEntry( 16 | string text, 17 | Color color, 18 | bool blink) 19 | { 20 | Text = text; 21 | Color = color; 22 | IsExecuting = blink; 23 | } 24 | 25 | public Color Color { get; private set; } 26 | 27 | public string Text { get; private set; } 28 | 29 | public bool IsExecuting { get; set; } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /UsageControl/UsageHistoryControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace UsageControl 7 | { 8 | /// 9 | /// Summary description for UsageHistoryControl. 10 | /// 11 | public class UsageHistoryControl : UserControl 12 | { 13 | /// 14 | /// Required designer variable. 15 | /// 16 | private Container components = null; 17 | 18 | private const int squareWidth = 12; 19 | private const int maxLastValuesCount = 2000; 20 | private const int shiftStep = 3; 21 | 22 | private int shift = 0; 23 | 24 | private int [] lastValues1 = new int[maxLastValuesCount]; 25 | private int [] lastValues2 = new int[maxLastValuesCount]; 26 | private int nextValueIndex; 27 | private int lastValuesCount; 28 | 29 | private int max = 100; 30 | private int min = 0; 31 | 32 | public UsageHistoryControl() 33 | { 34 | // This call is required by the Windows.Forms Form Designer. 35 | InitializeComponent(); 36 | 37 | EnableDoubleBuffering(); 38 | Reset(); 39 | } 40 | 41 | public void Reset() 42 | { 43 | lastValues1.Initialize(); 44 | lastValues2.Initialize(); 45 | nextValueIndex = 0; 46 | lastValuesCount = 0; 47 | Invalidate(); 48 | } 49 | 50 | /// 51 | /// Clean up any resources being used. 52 | /// 53 | protected override void Dispose( bool disposing ) 54 | { 55 | if( disposing ) 56 | { 57 | if(components != null) 58 | { 59 | components.Dispose(); 60 | } 61 | } 62 | base.Dispose( disposing ); 63 | } 64 | 65 | #region Component Designer generated code 66 | /// 67 | /// Required method for Designer support - do not modify 68 | /// the contents of this method with the code editor. 69 | /// 70 | private void InitializeComponent() 71 | { 72 | // 73 | // UsageHistoryControl 74 | // 75 | this.BackColor = System.Drawing.Color.Black; 76 | this.Name = "UsageHistoryControl"; 77 | 78 | } 79 | #endregion 80 | 81 | private void EnableDoubleBuffering() 82 | { 83 | // Set the value of the double-buffering style bits to true. 84 | SetStyle(ControlStyles.DoubleBuffer | 85 | ControlStyles.UserPaint | 86 | ControlStyles.AllPaintingInWmPaint, 87 | true); 88 | UpdateStyles(); 89 | } 90 | 91 | protected override void OnResize(EventArgs e) 92 | { 93 | // Invalidate the control to get a repaint. 94 | Invalidate(); 95 | } 96 | 97 | protected override void OnPaint(PaintEventArgs e) 98 | { 99 | Graphics g = e.Graphics; 100 | 101 | for(int i = 0; i <= ClientRectangle.Width+squareWidth; i += squareWidth) 102 | { 103 | g.DrawLine(Pens.Green, i-shift, 0, i-shift, ClientRectangle.Height); 104 | } 105 | 106 | for(int i = 0; i < ClientRectangle.Height; i += squareWidth) 107 | { 108 | g.DrawLine(Pens.Green, 0, i, ClientRectangle.Width, i); 109 | } 110 | 111 | int startValueIndex = (nextValueIndex-1+maxLastValuesCount)%maxLastValuesCount; 112 | 113 | int prevVal1 = GetRelativeValue(lastValues1[startValueIndex]); 114 | int prevVal2 = GetRelativeValue(lastValues2[startValueIndex]); 115 | 116 | for(int i = 1; i < lastValuesCount; ++i) 117 | { 118 | int index = nextValueIndex - 1 - i; 119 | if (index < 0) 120 | { 121 | index += maxLastValuesCount; 122 | } 123 | 124 | int val1 = GetRelativeValue(lastValues1[index]); 125 | int val2 = GetRelativeValue(lastValues2[index]); 126 | 127 | g.DrawLine( 128 | Pens.Red, 129 | ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal2, 130 | ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val2); 131 | 132 | g.DrawLine( 133 | Pens.LawnGreen, 134 | ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal1, 135 | ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val1); 136 | 137 | prevVal1 = val1; 138 | prevVal2 = val2; 139 | } 140 | } 141 | 142 | private int GetRelativeValue(int val) 143 | { 144 | int result = val * (ClientRectangle.Height-2) / max + 1; 145 | return result; 146 | } 147 | 148 | public void AddValues(int val1, int val2) 149 | { 150 | lastValues1[nextValueIndex] = val1; 151 | lastValues2[nextValueIndex] = val2; 152 | 153 | nextValueIndex++; 154 | nextValueIndex %= maxLastValuesCount; 155 | lastValuesCount++; 156 | if (lastValuesCount > maxLastValuesCount) 157 | { 158 | lastValuesCount = maxLastValuesCount; 159 | } 160 | 161 | shift += shiftStep; 162 | shift %= squareWidth; 163 | Invalidate(); 164 | } 165 | 166 | public int Maximum 167 | { 168 | get 169 | { 170 | return max; 171 | } 172 | 173 | set 174 | { 175 | // Make sure that the maximum value is never set lower than the minimum value. 176 | if (value < min) 177 | { 178 | min = value; 179 | } 180 | 181 | max = value; 182 | 183 | // Invalidate the control to get a repaint. 184 | Invalidate(); 185 | } 186 | } 187 | 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace WorkItemsGroupDemo 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | public static void Main() 13 | { 14 | Form1.Init(); 15 | 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | Application.Run(new Form1()); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("WindowsApplication1")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("WindowsApplication1")] 9 | [assembly: AssemblyCopyright("Copyright © 2006")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: ComVisible(false)] 13 | [assembly: Guid("68872ba4-6524-406b-9c96-cf8ca3f4c729")] 14 | [assembly: AssemblyVersion("1.0.0.0")] 15 | [assembly: AssemblyFileVersion("1.0.0.0")] 16 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WorkItemsGroupDemo.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorkItemsGroupDemo.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WorkItemsGroupDemo.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.1.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/WorkItemsGroupDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD} 9 | WinExe 10 | Properties 11 | WorkItemsGroupDemo 12 | WorkItemsGroupDemo 13 | WorkItemsGroupDemo.Program 14 | 15 | 16 | 3.5 17 | 18 | 19 | v4.6 20 | 21 | 22 | 23 | true 24 | full 25 | false 26 | bin\Windows\Debug\ 27 | TRACE;DEBUG;_WINDOWS 28 | prompt 29 | 4 30 | false 31 | false 32 | 33 | 34 | none 35 | true 36 | bin\Windows\Release\ 37 | TRACE;_WINDOWS 38 | prompt 39 | 4 40 | false 41 | 42 | 43 | ..\publish\dist\demos\Windows\WorkItemsGroupDemo\ 44 | TRACE;_WINDOWS 45 | true 46 | AnyCPU 47 | bin\Windows\Release\WorkItemsGroupDemo.exe.CodeAnalysisLog.xml 48 | true 49 | GlobalSuppressions.cs 50 | prompt 51 | MinimumRecommendedRules.ruleset 52 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 53 | false 54 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 55 | false 56 | false 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Form 69 | 70 | 71 | Form1.cs 72 | 73 | 74 | 75 | 76 | Designer 77 | Form1.cs 78 | 79 | 80 | ResXFileCodeGenerator 81 | Resources.Designer.cs 82 | Designer 83 | 84 | 85 | True 86 | Resources.resx 87 | True 88 | 89 | 90 | 91 | SettingsSingleFileGenerator 92 | Settings.Designer.cs 93 | 94 | 95 | True 96 | Settings.settings 97 | True 98 | 99 | 100 | 101 | 102 | {52f1074c-33af-4cbc-885b-dff14a4b4442} 103 | SmartThreadPool 104 | 105 | 106 | {C11A4561-CCB5-4C96-8DF2-B804031D89D8} 107 | UsageControl 108 | 109 | 110 | 111 | 118 | -------------------------------------------------------------------------------- /WorkItemsGroupDemo/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | --------------------------------------------------------------------------------