[英]What is the difference between these two methods for pausing/resuming threads?
我有一個多線程應用程序,用於從網站中提取數據。 我希望能夠從UI暫停和恢復多個線程。 在網上搜索后,我了解了兩種可用於控制(暫停/恢復)線程的方法。
使用Monitor類。
我有一個名為GetHtml
的函數, GetHtml
返回網站的html。 為簡潔起見,我只是展示了這個功能的一小部分。
public string GetHtml(string url, bool isProxy = false)
{
string result = "";
ExecutionGateway();
//->> EXTRA CODE FOR FETCHING HTML
return result;
}
我有一個函數ControlTasks
用於從UI控制線程,下面我已經使用Monitor
類和EventWaitHandle
類使用兩種線程控制方法解釋了ControlTasks
函數(我還將簡要解釋函數ExecutionGateway
的工作)。
1.使用Monitor
類
private object taskStopper = new object();
public bool ControlTasks(bool isPause)
{
try
{
if (isPause)
{
Monitor.Enter(taskStopper);
}
else
{
Monitor.Exit(taskStopper);
}
return true;
}
catch (Exception ex)
{
Logger.Instance.WriteLog("ControlTasks:", ex, Logger.LogTypes.Error);
return false;
}
}
從UI調用ControlTasks
,如果isPause
為true,則在對象taskStopper
上使用獨占鎖,否則釋放鎖。現在,函數ExecutionGateway
用於獲取對象taskStopper
鎖,但它不執行任何操作,如下面的代碼所示。
private void ExecutionGateway()
{
lock(taskStopper){ }
}
這樣,當ControlTasks
isPause
為true時,所有正在運行的線程都進入等待狀態,因為taskStopper
是獨占鎖定的,如果isPause
為false,則所有線程都會恢復其處理。
2.使用EventWaitHandle
類
private EventWaitHandle handle = new ManualResetEvent(true);
public bool ControlTasks(bool isPause)
{
try
{
if (isPause)
{
handle.Reset();
}
else
{
handle.Set();
}
return true;
}
catch (Exception ex)
{
Logger.Instance.WriteLog("ControlTasks:", ex, Logger.LogTypes.Error);
return false;
}
}
此代碼也從根本上執行相同的工作,其中事件狀態根據isPause
參數發出信號/不發信號。 現在,相應的ExecutionGateway
方法。
private void ExecutionGateway()
{
handle.WaitOne(Timeout.Infinite);
}
這兩種方法有什么區別,哪一方比另一方好? 有沒有其他方法可以做到這一點?
我多次面臨的主要問題是,如果我使用上述方法中的任何一種,並且我有100個線程; 當我暫停它們,然后在5分鍾或更長時間后恢復它們,UI開始掛起。 用戶界面非常反應遲鈍。 它會得到更新但仍然保持掛起狀態,並且每隔一段時間我就會收到“無響應”消息。 有一件事我想提到每個線程提取數據並通知UI有關通過事件處理獲取的數據。 這種反應遲鈍的原因是什么? 這是我的方法的問題嗎?
我認為總是希望使用一種能夠清楚地傳達你意圖的結構。 你想要一個他們應該等待的其他線程的信號 (即停止做他們正在做的事情),直到你發信號通知他們可以重新開始。 您有一個控制線程(您的UI),並且可能有許多線程正在進行工作並將結果編組回UI。
方法1並不理想,因為鎖(至少在我的經驗中)最常用於保護不適合在多線程代碼中使用的資源。 例如,寫入共享字段。
方法2更有意義,手動重置事件就像一個門:打開門,事物可以通過,關閉它,他們不能。 這正是您正在尋找的行為,我認為大多數開發人員會很快理解這是您的意圖。
至於你的第二個問題,聽起來你正在收到阻塞UI的消息。 如果你停止所有100個線程然后同時啟動它們,那么他們很可能會完全靠近地完成他們的工作,並且所有人都試圖將他們的工作結果發送到UI線程。 要解決此問題,您可以嘗試在重新啟動或使用較少線程時錯開工作。 另一種選擇是聚合結果,並且每x秒只調度一次UI - 但這樣做更多一些。
在選項1中,使用Monitor
類意味着一次只有一個線程擁有監視器對象的獨占鎖。 這意味着在你的100個線程中,一次只有1個處理,這種方式違背了使用線程的目的。 這也意味着您的GUI線程必須等到當前工作線程完成才能獲得鎖定。
ManualResetEvent
是一個更好的選擇,因為它用於在線程之間發出信號 ,而不是防止多線程訪問。
我不知道為什么你的GUI使用第二個選項沒有響應,但我不認為它與你的手動重置事件有關。 更有可能你有一個不同的問題,GUI線程被淹沒。 你建議你有100個線程都向GUI發送通知事件,這似乎可能是罪魁禍首。
如果您調試應用程序會發生什么,並且只是在GUI無響應時隨機中斷? 多次這樣做應該顯示你的GUI線程是什么以及瓶頸在哪里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.