这个类主要是利用了Task建立了一个一个工作列表,
/********************************************************************
created: 2013/01/21
created: 21:1:2013 16:34
use: ThreadData study = new ThreadData();
study.SearchFlag = SearchThreadFlag.LocalDB;
study.Operation = GetStudy;
study.LevelFlag = LoadThreadFlag.Study;
study.Param = "study1";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref study);
//call RunningTask.Result to Wait thread exit. It will block current thread.
bool isStudyOk = study.RunningTask.Result;
默认的Task Scheduler是FIFO(先进先出)。每次把要执行的Task加载到Queue里,然后顺序执行,每次执行前先根据优先级(比如Study〉Series〉Image)来对队列前面的Task进行Cancel,防止有些置前的Task因为计算量大而覆盖了后续Task的结果。
*********************************************************************/
//use this macro to enable/disable logger information.
//#define TaskLogger
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Commons
{
//Unit Test
/// <summary>
///A test for CreateInstance
///</summary>
public void CreateInstanceTest()
{
ThreadHelperSingleton actual;
actual = ThreadHelperSingleton.CreateInstance();
}
/// <summary>
///A test for QueueUserWorkItem
///</summary>
public void QueueUserWorkItemNormalTest()
{
bool actual;
System.Diagnostics.Debug.WriteLine("Begin to run QueueUserWorkItemNormalTest, queue is (All,Worklist,LocalDB,Study1,Seies1,Image1,Study2,Image2,Seires2,Series3,Image3).");
//Get All
ThreadData all = new ThreadData();
all.SearchFlag = SearchThreadFlag.All;
all.Operation = GetAll;
actual = ThreadHelperSingleton.QueueUserWorkItem(ref all);
//bool isAllOk = all.RunningTask.Result;
//Get Worklist
ThreadData worklist = new ThreadData();
worklist.SearchFlag = SearchThreadFlag.Worklist;
worklist.Operation = GetWorklist;
worklist.Param = "worklist1";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref worklist);
//bool isWorklist = worklist.RunningTask.Result;
//Get LocalDB
ThreadData localDB = new ThreadData();
localDB.SearchFlag = SearchThreadFlag.LocalDB;
localDB.Operation = GetLocalDB;
localDB.LevelFlag = LoadThreadFlag.All;
localDB.Param = "local db";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref localDB);
//bool isLocalDB = localDB.RunningTask.Result;
//Get Study
ThreadData study = new ThreadData();
study.SearchFlag = SearchThreadFlag.LocalDB;
study.Operation = GetStudy;
study.LevelFlag = LoadThreadFlag.Study;
study.Param = "study1";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref study);
//bool isStudyOk = study.RunningTask.Result;
//Get Series
ThreadData series = new ThreadData();
series.SearchFlag = SearchThreadFlag.LocalDB;
series.Operation = GetSeries;
series.LevelFlag = LoadThreadFlag.Series;
series.Param = "series1";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref series);
//bool isSeriesOk = series.RunningTask.Result;
//Get Image
ThreadData image = new ThreadData();
image.SearchFlag = SearchThreadFlag.LocalDB;
image.Operation = GetImage;
image.LevelFlag = LoadThreadFlag.Image;
image.Param = "image1";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref image);
//bool isLoadImageOK = image.RunningTask.Result;
//Get Study2
ThreadData study2 = new ThreadData();
study2.SearchFlag = SearchThreadFlag.LocalDB;
study2.Operation = GetStudy;
study2.LevelFlag = LoadThreadFlag.Study;
study2.Param = "study2";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref study2);
//bool isStudyOk2 = study2.RunningTask.Result;
//Get Image2
ThreadData image2 = new ThreadData();
image2.SearchFlag = SearchThreadFlag.LocalDB;
image2.Operation = GetImage;
image2.LevelFlag = LoadThreadFlag.Image;
image2.Param = "image2";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref image2);
//bool isLoadImageOK2 = image2.RunningTask.Result;
//Get Series2
ThreadData series2 = new ThreadData();
series2.SearchFlag = SearchThreadFlag.LocalDB;
series2.Operation = GetSeries;
series2.LevelFlag = LoadThreadFlag.Series;
series2.Param = "series2";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref series2);
//bool isSeriesOk2 = series2.RunningTask.Result;
//Get Series3
ThreadData series3 = new ThreadData();
series3.SearchFlag = SearchThreadFlag.LocalDB;
series3.Operation = GetSeries;
series3.LevelFlag = LoadThreadFlag.Series;
series3.Param = "series3";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref series3);
//bool isSeriesOk3 = series3.RunningTask.Result;
//Get Image3
ThreadData image3 = new ThreadData();
image3.SearchFlag = SearchThreadFlag.LocalDB;
image3.Operation = GetImage;
image3.LevelFlag = LoadThreadFlag.Image;
image3.Param = "image3";
actual = ThreadHelperSingleton.QueueUserWorkItem(ref image3);
//bool isLoadImageOK3= image3.RunningTask.Result;
System.Diagnostics.Debug.WriteLine("QueueUserWorkItemNormalTest run successfully.");
}
private bool GetStudy(object study)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
System.Diagnostics.Debug.WriteLine("Get study successfully. " + (study ?? "") + DateTime.Now.ToString(" yyyy-MM-dd HH:mm:ss.f"));
return true;
}
private bool GetSeries(object series)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
System.Diagnostics.Debug.WriteLine("Get series successfully. " + (series ?? "") + DateTime.Now.ToString(" yyyy-MM-dd HH:mm:ss.f"));
return true;
}
private bool GetImage(object image)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
System.Diagnostics.Debug.WriteLine("Get image successfully. " + (image ?? "") + DateTime.Now.ToString(" yyyy-MM-dd HH:mm:ss.f"));
return true;
}
private bool GetWorklist(object worklist)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
System.Diagnostics.Debug.WriteLine("Get worklist successfully. " + (worklist ?? "") + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.f"));
return true;
}
private bool GetLocalDB(object database)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
GetStudy(database.ToString() + "'s Study");
GetSeries(database.ToString() + "'s Series");
GetImage(database.ToString() + "'s Image");
System.Diagnostics.Debug.WriteLine("Get database successfully. " + (database ?? "") + DateTime.Now.ToString(" yyyy-MM-dd HH:mm:ss.f"));
return true;
}
private bool GetAll(object all)
{
Random rand = new Random();
Thread.Sleep(rand.Next(100));
GetWorklist("all worklist");
GetLocalDB("all database");
System.Diagnostics.Debug.WriteLine("Get All successfully. " + (all ?? "") + DateTime.Now.ToString(" yyyy-MM-dd HH:mm:ss.f"));
return true;
}
public enum SearchThreadFlag
{
LocalDB = 0,
Worklist = 1,
All = 2,
}
public enum LoadThreadFlag
{
None = 0,
Study = 1,
Series = 2,
Rawdata = 3,
Report = 4,
Image = 5,
All = 6,
}
public class ThreadData
{
public SearchThreadFlag SearchFlag { get; set; }
public LoadThreadFlag LevelFlag { get; set; }
public Func<object, bool> Operation { get; set; }
public Action Callback {get; set; }
public object Param { get; set; }
public CancellationTokenSource CancelHandler { get; internal set; }
public Task<bool> RunningTask { get; internal set; }
}
public class ThreadHelperSingleton
{
public static Dictionary<ThreadData, Task<bool>> TaskPool { get; internal set; }
private static ThreadHelperSingleton instance;
private ThreadHelperSingleton()
{
}
public static ThreadHelperSingleton CreateInstance()
{
if (null == instance)
{
instance = new ThreadHelperSingleton();
}
return instance;
}
public static bool QueueUserWorkItem(ref ThreadData data)
{
if (null == data)
{
data = null;
return false;
}
if (null == data.Operation)
{
data = null;
return false;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(QueueUserWorkItem)Begin to QueueUserWorkItem." + " SearchFlag is " + data.SearchFlag + ", LevelFlag is " + data.LevelFlag);#endif
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(QueueUserWorkItem)Before StartThread, TaskPool's count is " + TaskPool.Count);#endif
//
StopPreThread(data);
//
bool isOk = StartThread(data);
if (!isOk)
{
data = null;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(QueueUserWorkItem)After StartThread, TaskPool's count is " + (TaskPool != null ? TaskPool.Count : 0));#endif
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(QueueUserWorkItem)End QueueUserWorkItem." + " SearchFlag is " + data.SearchFlag + ", LevelFlag is " + data.LevelFlag);#endif
return isOk;
}
private static bool StartThread(ThreadData data)
{
if (null == data)
{
return false;
}
if (null == data.Operation)
{
return false;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)Begin to StartThread.");#endif
if (null == TaskPool
|| 0 == TaskPool.Count)
{
if (null == TaskPool)
{
TaskPool = new Dictionary<ThreadData, Task<bool>>();
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)TaskPool is empty, directly to add new task.");#endif
StartNewTask(data);
}
else
{
if (data.SearchFlag.Equals(SearchThreadFlag.All))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)SearchFlag is All, it not need to attach task to parent task.");#endif
StartNewTask(data);
}
else if (data.SearchFlag.Equals(SearchThreadFlag.Worklist))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)SearchFlag is worklist, it not need to attach task to parent task.");#endif
StartNewTask(data);
}
else if (data.SearchFlag.Equals(SearchThreadFlag.LocalDB))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)SearchFlag is localDB, begin to start new task by level flag.");#endif
//Current we use synchronized rule to load data, so it not need attach sub task to parent task.
//We use StartNewTask to create a normal task.
//StartSubTask(data);
StartNewTask(data);
}
else
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)SearchFlag is unknown, use StartNewTask to create default task.");#endif
StartNewTask(data);
}
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartThread)End StartThread.");#endif
return true;
}
private static bool StopPreThread(ThreadData data)
{
if (null == data)
{
return false;
}
if (null == data.Operation)
{
return false;
}
if (null == TaskPool
|| 0 == TaskPool.Count)
{
return true;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)Begin to StopPreThread");#endif
IList<KeyValuePair<ThreadData, Task<bool>>> tasks = null;
if (data.SearchFlag.Equals(SearchThreadFlag.All))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)SearchFlag is All.");#endif
tasks = TaskPool.ToList();
}
else if (data.SearchFlag.Equals(SearchThreadFlag.Worklist))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)SearchFalg is Worklist.");#endif
tasks = TaskPool.ToList();
}
else if (data.SearchFlag.Equals(SearchThreadFlag.LocalDB))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)SearchFlag is LocalDB");#endif
if (data.LevelFlag.Equals(LoadThreadFlag.All))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("LevelFlag is All.");#endif
tasks = TaskPool.ToList();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Study))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)LevelFlag is Study.");#endif
tasks = TaskPool.ToList();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Series))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)LevleFlag is Series.");#endif
tasks = TaskPool.Where(d =>
d.Key.SearchFlag.Equals(SearchThreadFlag.LocalDB)
&& (d.Key.LevelFlag.Equals(LoadThreadFlag.Series)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.Image)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.All)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.None)
)
).ToList();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Rawdata))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)LevleFlag is Rawdata.");#endif
tasks = TaskPool.Where(d =>
d.Key.SearchFlag.Equals(SearchThreadFlag.LocalDB)
&& (d.Key.LevelFlag.Equals(LoadThreadFlag.Rawdata)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.All)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.None)
)
).ToList();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Report))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)LevleFlag is Report.");#endif
tasks = TaskPool.Where(d =>
d.Key.SearchFlag.Equals(SearchThreadFlag.LocalDB)
&& (d.Key.LevelFlag.Equals(LoadThreadFlag.Report)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.All)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.None)
)
).ToList();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Image))
{
tasks = TaskPool.Where(d =>
d.Key.SearchFlag.Equals(SearchThreadFlag.LocalDB)
&& (d.Key.LevelFlag.Equals(LoadThreadFlag.Image)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.All)
|| d.Key.LevelFlag.Equals(LoadThreadFlag.None)
)
).ToList();
}
else
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)SearchFlag is unknown, it will clear all Tasks.");#endif
tasks = TaskPool.ToList();
}
}
else
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)SearchFlag is unknown, it will clear all Tasks.");#endif
tasks = TaskPool.ToList();
}
if (null != tasks && 0 != tasks.Count)
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)Remove Task count is " + tasks.Count);#endif
int count = tasks.Count;
for (int i = 0; i < count; i++)
{
#if TaskLooger
System.Diagnostics.Debug.WriteLine("(StopPreThread)Cancel task id is " + tasks[i].Value.Id + ", SearchFlag is " + tasks[i].Key.SearchFlag + ", LevelFlag is " + tasks[i].Key.LevelFlag);#endif
if (null != tasks[i].Key.CancelHandler)
{
tasks[i].Key.CancelHandler.Cancel();
}
TaskPool.Remove(tasks[i].Key);
tasks[i].Key.RunningTask = null;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)Remove Task finished.");#endif
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StopPreThread)End StopPreThread.");#endif
return true;
}
private static bool StartNewTask(ThreadData data)
{
if (null == data
|| null == data.Operation)
{
return false;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartNewTask)Begin to start new task.");#endif
var tokenSource = new CancellationTokenSource();
Task<bool> task = Task<bool>.Factory.StartNew(data.Operation, data.Param, tokenSource.Token);
if (null != task && null != data.Callback)
{
task.ContinueWith(t => { var exp = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith(delegate { data.Callback(); })
.ContinueWith(t => { var exp = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted);
}
data.CancelHandler = tokenSource;
data.RunningTask = task;
if (null != task)
{
TaskPool.Add(data, task);
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartNewTask)Add task to TaskPool, id is " + task.Id + ", SearchFlag " + data.SearchFlag + ", LevelFlag " + data.LevelFlag); System.Diagnostics.Debug.WriteLine("(StartNewTask)End StartNewTask");#endif
return true;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartNewTask)End StartNewTask");#endif
return false;
}
private static bool StartSubTask(ThreadData data)
{
if (null == data
|| null == data.Operation)
{
return false;
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)Begin to StartSubTask");#endif
KeyValuePair<ThreadData, Task<bool>> parentTask = new KeyValuePair<ThreadData, Task<bool>>();
if (data.LevelFlag.Equals(LoadThreadFlag.All))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)LevelFlag is All, it not need to attach task to parent task.");#endif
StartNewTask(data);
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Study))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)LevelFlag is Study, it not need to attach task to parent task.");#endif
StartNewTask(data);
}
else
{
if (data.LevelFlag.Equals(LoadThreadFlag.Series))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)LevelFlag is Series.");#endif
parentTask = TaskPool.Where(t =>
t.Key.LevelFlag.Equals(LoadThreadFlag.Study)
).FirstOrDefault();
}
else if (data.LevelFlag.Equals(LoadThreadFlag.Image))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)LevelFlag is Image.");#endif
parentTask = TaskPool.Where(t =>
t.Key.LevelFlag.Equals(LoadThreadFlag.Series)
).FirstOrDefault();
}
//Create child task.
if (null != parentTask.Value
&& !parentTask.Value.Status.Equals(TaskStatus.RanToCompletion)
&& !parentTask.Value.Status.Equals(TaskStatus.Canceled)
&& !parentTask.Value.Status.Equals(TaskStatus.Faulted))
{
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)Start to attach sub task to parent task.");#endif
var subTask = parentTask.Value.ContinueWith(
delegate { return data.Operation(data.Param); },
parentTask.Key.CancelHandler.Token,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default
);
//parentTask.Value.Start();
data.CancelHandler = parentTask.Key.CancelHandler;
data.RunningTask = subTask;
TaskPool.Add(data, subTask);
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)Add task to TaskPool, id is " + subTask.Id + ", SearchFlag " + data.SearchFlag + ", LevelFlag " + data.LevelFlag);#endif
}
else
{
StartNewTask(data);
}
}
#if TaskLogger
System.Diagnostics.Debug.WriteLine("(StartSubTask)End StartSubTask");#endif
return true;
}
}
}