繁体   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