簡體   English   中英

暫停/恢復線程的這兩種方法有什么區別?

[英]What is the difference between these two methods for pausing/resuming threads?

我有一個多線程應用程序,用於從網站中提取數據。 我希望能夠從UI暫停和恢復多個線程。 在網上搜索后,我了解了兩種可用於控制(暫停/恢復)線程的方法。

  1. 使用Monitor類。

  2. 使用EventWaitHandleManualResetEvent類。


我做了什么:

我有一個名為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);
}

問題:

  1. 這兩種方法有什么區別,哪一方比另一方好? 有沒有其他方法可以做到這一點?

  2. 我多次面臨的主要問題是,如果我使用上述方法中的任何一種,並且我有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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM