我有一個對象,一個時間軸,封裝線程。活動可以安排在時間表上;該線程將等待執行任何事件,執行它並返回睡眠狀態(無論是(a)到達下一個事件所需的時間,還是(b)如果沒有其他事件,則無限期地)。正確的方法清理C#中的永久線程
使用WaitEventHandle處理睡眠,當事件列表發生更改(因爲可能需要調整睡眠延遲)或應停止線程(因此線程可以正常終止)時觸發WaitEventHandle。
析構函數調用Stop(),我甚至實現了IDisposable和Dispose()也調用Stop()。
但是,當我在窗體應用程序中使用此組件時,我的應用程序將永遠不會正常關閉時關閉窗體。出於某種原因,Stop()永遠不會被調用,因此,在決定等待所有線程完成之前,我的對象的析構函數都不會觸發,也不會調用Dispose()方法。
我想解決方法是在FormClose事件中顯式調用Dispose()我自己,但由於這個類將在庫中,和它實際上是一個更深的層(也就是應用程序開發人員將永遠不會看到Timeline類),這對於應用程序開發人員來說似乎非常醜陋和額外的(不必要的)陷阱。在資源發佈成爲問題時,我通常使用的using()子句不適用,因爲這將是一個長期存在的對象。一方面,我可以理解,.NET將在所有線程完成最後一輪垃圾收集之前等待所有線程完成,但在這種情況下會產生非常笨拙的情況。
如何在不向我的圖書館消費者添加要求的情況下正確地清理自己的線索?換句話說,當應用程序正在退出時,如何讓.NET通知我的對象,但在它等待所有線程完成之前呢?
編輯:在迴應的人說,這是可以的客戶端程序要知道的線程:我恭敬地不同意。
正如我在我原來的文章中所說的,線程隱藏在另一個對象(動畫師)中。我爲另一個對象實例化一個Animator,然後告訴它執行動畫,例如「使這盞燈閃爍800毫秒」。作爲Animator對象的使用者,我不在乎Animator如何確保燈光正好閃爍800毫秒。它是否啓動線程?我不在乎。它是否創建一個隱藏的窗口並使用系統計時器(ew)?我不在乎。它是否僱傭侏儒來打開和關閉我的燈光?我不在乎。
而我特別是不希望不得不在意如果我創建了Animator,我必須跟蹤它,並在我的程序退出時調用一個特殊的方法,而不是每個其他對象。它應該是圖書館實施者而不是圖書館消費者的關注點。
編輯:代碼實際上足夠短顯示。我將它列入參考,SANS方法的事件添加到列表:
internal class Timeline : IDisposable {
private Thread eventThread;
private volatile bool active;
private SortedList<DateTime, MethodInvoker> events = new SortedList<DateTime,MethodInvoker>();
private EventWaitHandle wakeup = new EventWaitHandle(false, EventResetMode.AutoReset);
internal Timeline() {
active = true;
eventThread = new Thread(executeEvents);
eventThread.Start();
}
~Timeline() {
Dispose();
}
private DateTime NextEvent {
get {
lock(events)
return events.Keys[0];
}
}
private void executeEvents() {
while (active) {
// Process all events that are due
while (events.Count > 0 && NextEvent <= DateTime.Now) {
lock(events) {
events.Values[0]();
events.RemoveAt(0);
}
}
// Wait for the next event, or until one is scheduled
if (events.Count > 0)
wakeup.WaitOne((int)(NextEvent - DateTime.Now).TotalMilliseconds);
else
wakeup.WaitOne();
}
}
internal void Stop() {
active = false;
wakeup.Set();
}
public void Dispose() {
Stop();
}
}
+1 - 在您明確設置了自己的線程對象的時候,您(以及任何調用您的庫)負責告訴它停止,而不是.NET – 2009-02-17 22:38:19