[英]C# ThreadPool and ElapsedEventHandler
我的應用程序應該在30分鍾內完成。 應用程序的組件使用線程池運行。
所以
//queue first all the components
//when the Collect method for each of the components finishes it will set the event
ManualResetEvent serverEvent = new ManualResetEvent(false);
sectionsCompleted.Add(serverEvent);
ThreadPool.QueueUserWorkItem(serverInfo.Collect,"ServerInfo ");
ManualResetEvent cpuEvent= new ManualResetEvent(false);
sectionsCompleted.Add(cpuEvent);
ThreadPool.QueueUserWorkItem(cpuInfo.Collect,"CPUInfo ");
//then wait for all the components to finish
WaitHandle.WaitAll(sectionsCompleted.ToArray());
因此,邏輯是調用ThreadPool中的所有組件並使用ManualResetEvent類來通知組件已完成的主線程。
現在我想使用ElapsedEvent Handler來確保代碼在某個時間范圍內(例如30分鍾)正常完成。 所以30分鍾后如果還有一些線程正在運行我想要中止它們。
所以我的問題是ElapsedEventHandler委托會被調用嗎? 或者主線程是否會等待WaitHandle.WaitAll(sectionsCompleted.ToArray()) ?
有沒有其他方法可以實現在一段時間間隔后停止線程池中的所有線程的此功能。
如果你設置了計時器,計時器的事件處理程序,並在上面的代碼之前 (或至少在WaitAll
之前)啟動計時器然后
Elapsed
事件會被觸發, WaitAll
等待 但你可以輕松地做一些事情:
if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
// did not finish in the 30 minute timespan, so kill the threads
}
如果你執行上述操作,則不必擔心為計時器同步事件處理程序(可能會在完成時嘗試殺死線程)和等待WaitHandles的Main方法(因此可能會在事件處理程序認為該線程正在被殺死)。
如果你能夠(依賴於.NET版本)那么Task
就非常適合這個,因為你可以使用CancellationToken
來讓你在沒有完成的情況下優雅地殺死每個任務。 有關如下內容的信息,請參閱MSDN:任務取消 。 如果你不能使用Task
你可以自己連接同一個解決方案。 一種可能的技術是使用更多的WaitHandles(也見下文)。
此方法還允許您將Wait + Cancel代碼移動到單獨的線程中。 因此,您可以在創建工作線程后立即釋放UI或主代碼線程。 這具有額外的優點,您還可以從控制線程發信號通知Wait + Cancel代碼的單個實例以觸發過早取消。
// use the same CancellationTokenSource to create all tasks
var tokenSource2 = new CancellationTokenSource();
// for each task, use the following structure
CancellationToken ct = tokenSource2.Token;
var task = Task.Factory.StartNew(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
// make sure any loops and other methods check the ct.IsCancellationRequested regularly
while (moreToDo)
{
if (ct.IsCancellationRequested)
{
// Clean up any resources, transactions etc. here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token); // Pass same token to StartNew.
// add each task to the tasks list
tasks.Add(task);
// once all tasks created, wait on them and cancel if they overrun
// by passing the token, another thread could even cancel the whole operation ahead of time
if (!Task.WaitAll(tasks.ToArray(), (int)TimeSpan.FromMinutes(30).TotalMilliseconds,
tokenSource2.Token))
{
// did not finish in the 30 minute timespan, so kill the threads
tokenSource2.Cancel();
try
{
// Now wait for the tasks to cancel
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
// handle any unexpected task exceptions here
}
}
或者在沒有任務的.NET 2.0中:
// in Main thread ...
ManualResetEvent serverEventCancelled = new ManualResetEvent(false);
cancellationMres.Add(serverEventCancelled);
// Inside the thread, do this regularly - zero timeout returns instantly ...
if (serverEventCancelled.WaitOne(0))
{
// do cancellation and ...
// now set the "completed" waithandle (or do something similar to let Main know we are done)
serverEvent.Set();
return;
}
// In Main thread ...
if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
foreach (var cancellationMre in cancellationMres)
{
cancellationMre.Set();
}
WaitHandle.WaitAll(sectionsCompleted.ToArray());
}
是否會調用ElapsedEventHandler委托?
yes
主線程會等待WaitHandle.WaitAll(sectionsCompleted.ToArray())嗎?
yes
但是你需要在你的線程中發出eventhandler信號(比如cpuInfo.Collect),在.net 4.5中,你也可以使用CancellationTokenSource(TimeSpan)在一段時間后取消線程。
順便說一句:你應該把WaitHandle.WaitAll(sectionsCompleted.ToArray())放在非ui線程中,否則它會阻止你的UI。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.