我有一個很大程度上基於https://stackoverflow.com/a/1656662/782181生產者/消費者代碼的C#線程池類。注:我這樣做,而不是使用BlockingCollection,因爲我堅持使用.NET2.0!生產者/消費者線程池w /主線程支持 - 不常發生死鎖?
我在可以從主線程調用的類中添加了一個函數,以允許主線程執行一些工作。我的想法是,在某些時候,主線程等待工作完成,但不用等待,我也可以讓主線程完成一些工作來加快速度。
下面是類的精簡版本,以證明:
public static class SGThreadPool
{
// Shared object to lock access to the queue between threads.
private static object locker = new object();
// The various threads that are doing our work.
private static List<Thread> workers = null;
// A queue of tasks to be completed by the workers.
private static Queue<object> taskQueue = new Queue<object>();
private static Queue<WaitCallback> taskCallbacks = new Queue<WaitCallback>();
//OMMITTED: Init function (starts threads)
// Enqueues a task for a thread to do.
public static void EnqueueTask(WaitCallback callback, object context)
{
lock(locker)
{
taskQueue.Enqueue(context);
taskCallbacks.Enqueue(callback);
Monitor.PulseAll(locker); //Q: should I just use 'Pulse' here?
}
}
// Can be called from main thread to have it "help out" with tasks.
public static bool PerformTask()
{
WaitCallback taskCallback = null;
object task = null;
lock(locker)
{
if(taskQueue.Count > 0)
{
task = taskQueue.Dequeue();
}
if(taskCallbacks.Count > 0)
{
taskCallback = taskCallbacks.Dequeue();
}
}
// No task means no work, return false.
if(task == null || taskCallback == null) { return false; }
// Do the work!
taskCallback(task);
return true;
}
private static void Consume()
{
while(true)
{
WaitCallback taskCallback = null;
object task = null;
lock(locker)
{
// While no tasks in the queue, wait.
while(taskQueue.Count == 0)
{
Monitor.Wait(locker);
}
// Get a task.
task = taskQueue.Dequeue();
taskCallback = taskCallbacks.Dequeue();
}
// Null task signals an exit.
if(task == null || taskCallback == null) { return; }
// Call consume callback with task as context.
taskCallback(task);
}
}
}
基本上,我可以排隊到通過後臺線程來執行多項任務。但主線程也可以通過調用PerformTask()來執行任務。
我遇到了一個偶然的問題,主線程會嘗試在PerformTask()中「鎖定」,但鎖已經被佔用。主線程在等待,但由於某種原因,鎖定不可用。
代碼中沒有任何東西出現在導致死鎖的問題上 - 我希望別人能夠發現問題。我已經看了幾個小時,我不確定爲什麼主線程會卡在PerformTask()中的「lock()」調用中。似乎沒有其他線程會無限期地鎖定鎖定?允許主線程以這種方式與池交互是不是一個好主意?
也許,你想嘗試'BlockingCollection'而不是隊列+鎖 –
@ L.B,我真的認爲這將是偉大的,但我在Unity工作,它暫時停留在.NET2.0上!我會更新問題以表明這一點。 – kromenak