[英]Gracefully shutdown a thread
在我正在開發的應用程序中,我有一個主要表單,它只是位於那里並顯示日志數據,以及一個自動完成循環工作的工作線程。
MyWorker worker = new MyWorker();
MainForm mainForm = new MainForm();
// Subscribe form to log event so log data gets displayed
worker.Log += mainForm.Log;
// Start the worker thread's MainLoop
new Thread(new ThreadStart(worker.MainLoop)).Start();
// Show the form (blocking)
Application.Run(mainForm);
// If we end up here, the form has been closed and the worker has to stop running
worker.Running = false;
如您所見,無論何時關閉表單,都應該停止工作線程。 工人看起來像這樣:
public class MyWorker
{
public String Running { get; set; }
public MyWorker()
{
Running = true;
}
public void MainLoop()
{
while (Running)
{
DoExtensiveWork1();
if (!Running) return;
DoExtensiveWork2();
if (!Running) return;
DoExtensiveWork3();
if (!Running) return;
DoExtensiveWork4();
if (!Running) return;
DoExtensiveWork5();
if (!Running) return;
// We have to wait fifteen minutes (900 seconds)
// before another "run" can be processed
for (int i = 0; i < 900; i++)
{
Thread.Sleep(1000);
if (!Running) return;
}
}
}
}
如您所見,我希望線程能夠在連續的工作操作之間切換時停止,但不能在操作中停止。 當一個操作( DoExtensiveWorkN
)完成后,其狀態和結果將保持為磁盤或數據庫,因此在操作正在進行時退出(例如,通過Thread.Abort
)不是一個選項。
但是,我發現這個代碼我只是寫了一些令人厭惡的代碼,特別是“等待循環”,它休眠了一秒900次,以防止線程在檢測到Running
之前空閑15分鍾被設置為false
。
一旦完成一項工作,我寧願能夠拋出某種事件來阻止主循環。
任何人都可以指出我正確的方向如何做到這一點,或者如果需要完全重寫因為我完全誤解了線程,請告訴我哪些原則被解釋了?
您可以大大整理單個任務的運行和15分鍾的等待循環。
我建議也許使用這樣的東西:
public class MyWorker
{
private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
private readonly Action[] _workUnits;
private bool Running
{
get { return !_stopEvent.WaitOne(0); }
}
public MyWorker()
{
_workUnits = new Action[]
{
DoExtensiveWork1,
DoExtensiveWork2,
DoExtensiveWork3,
DoExtensiveWork4,
DoExtensiveWork5
};
}
public void Stop()
{
_stopEvent.Set();
}
public void MainLoop()
{
while (Running)
{
foreach (var workUnit in _workUnits)
{
workUnit();
if (!Running) return;
}
// We have to wait fifteen minutes (900 seconds)
// before another "run" can be processed
if (_stopEvent.WaitOne(900000)) return;
}
}
}
然后在下一個適當的點停止該過程:
Worker.Stop();
我建議使用System.Timers.Timer 。
您可以使用正在運行的東西來完成工作,而不是使用睡眠,您可以將計時器設置為在15分鍾后再次啟動。
如果你想提前停止它,那么調用某種中止方法(類似於設置你的Running = true變量)將停止計時器。
應該注意的是,每次定時器事件觸發時,它都會啟動一個新線程,因此你不必擔心殺死后台線程。 您的線程完成其處理運行,將計時器設置為在15分鍾內運行,然后線程自然完成。 如果你在等待期間中止,那么你只需擺脫計時器,不再需要清理。 如果你在運行期間中止,那么你讓運行結束,最后它檢查一個標志,不再啟動計時器,然后線程結束。
對於計時器,您需要將計時器設置為在過程結束時手動啟動。 另一種方法是讓計時器每15分鍾滴答一次,但這意味着如果你的處理需要10分鍾,那么它只能在下一次運行前5分鍾。 如果花了超過15分鍾,你可能會遇到麻煩。 手動重新啟動計時器也可確保在另一個計算機正在運行時不應重新啟動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.