【发布时间】:2014-08-11 13:04:07
【问题描述】:
我有一个用于从网站提取数据的多线程应用程序。我希望能够从 UI 暂停和恢复多个线程。在网上搜索后,我了解到两种方法可以用来控制(暂停/恢复)我的线程。
使用Monitor 类。
我做了什么:
我有一个名为GetHtml 的函数,它只返回网站的html。为了简洁起见,我只是展示了这个函数的小数部分。
public string GetHtml(string url, bool isProxy = false)
{
string result = "";
ExecutionGateway();
//->> EXTRA CODE FOR FETCHING HTML
return result;
}
我有一个函数ControlTasks 用于从UI 控制线程,下面我已经解释了ControlTasks 函数使用Monitor 类和EventWaitHandle 类的线程控制方法(我还将简要介绍解释函数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;
}
}
ControlTasks 从 UI 调用,如果 isPause 为真,则在对象 taskStopper 上使用排他锁,否则释放锁,现在是函数 ExecutionGateway,用于获取对象 @ 上的锁987654337@ 但它什么也不做,如下面的代码所示。
private void ExecutionGateway()
{
lock(taskStopper){ }
}
这样,当ControlTasks 中的isPause 为真时,所有正在运行的线程都进入等待状态,因为taskStopper 被独占锁定,如果isPause 为假,所有线程都将恢复其处理。
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 通过事件处理获取的数据。这种反应迟钝的原因可能是什么?我的方法有问题吗?
【问题讨论】:
-
我以前遇到过这种问题;我使用了
Monitor和Semaphore的组合。你可能想看看Semaphore。 -
使用方法 1 有一个相当大的缺陷...如果您的后台线程有很多争用,您的 UI 线程可能会在尝试获取锁时被阻止。
-
问题 2 与您阻塞 UI 线程 真的 长时间有关。当被阻塞时,UI 线程会将消息排队,当它恢复时,这些消息会被处理。一般来说,你应该尽量避免阻塞 UI 线程......
-
@James 但如果线程正在运行,那么它们应该在进入暂停状态之前处理所有 UI 消息,因为线程处于暂停状态,因此它们不会排队任何消息
标签: c# multithreading winforms