gpt4 book ai didi

c# - 在多线程应用中卡住

转载 作者:行者123 更新时间:2023-11-30 19:01:28 25 4
gpt4 key购买 nike

我正在尝试制作一个WinForms多线程应用程序,该应用程序无休止地在两个不同的线程中生成异常。

一个线程使用GenerateDllNotFoundExc()方法,另一个使用另一种方法,该方法基本相同,但只是生成另一个异常。

然后,它将异常消息写入队列,然后从队列写入文本框。

但是,GUI总是在1秒后冻结,它将消息稍微写入文本框并冻结。我尝试调试它,代码本身可以工作,但是GUI被冻结。

有人可以给我提示我做错了什么吗?

private delegate void GetQueueElem();
private event GetQueueElem getqueuelem;

private void GenerateDllNotFoundExc()
{
Action<String> addelem = new Action<String>(AddToQueue);

string exdll = string.Empty;

while (shouldgeneratemore)
{
try
{
throw new DllNotFoundException();
}
catch (Exception ex)
{
exdll = ex.Message;
}

this.Invoke(addelem, exdll);
}
}

private void AddToQueue(string exmess)
{
lock (lockobject)
queue.Enqueue(exmess);

getqueuelem.Invoke();
}

private void AddToTextBox()
{
while (queue.Count > 0)
{
string s = queue.Dequeue() +"\t" + Thread.CurrentThread.Name
+ "\t" + Thread.CurrentThread.ManagedThreadId + "\t";

lock (lockobject)
textBox1.Text += s;
}
}

最佳答案

这个问题是有教育意义的,它显示出具有所有三个主要线程错误的证据。按照它们的普遍程度粗略地排列它们:

  • 线程竞赛错误。当一个线程读取被另一个线程修改的变量时跳闸。需要锁定以免引起问题。此代码使用lock关键字,但使用不正确。 Queue类不是线程安全的,在此代码中,不安全地使用Count属性和Dequeue()方法都是没有锁的。但是,这里并不是实际的问题,使用Queue的代码实际上都不能在一个以上的线程上运行。换句话说,实际上并不需要该锁。
  • 死锁。当代码以不可预测的顺序获取锁时发生。对于在程序的UI线程上运行的代码特别讨厌,它通常获取不可见的锁,这些锁内置于.NET Framework,操作系统或各种第三方 Hook 中。例如屏幕阅读器。 Invoke()方法特别容易出现死锁,应避免使用,BeginInvoke()始终是首选方法。实际上,您实际上不需要Invoke(),也不在乎返回值。但是,即使它看起来很像死锁,也并不是该程序中的实际错误,您可以使用调试器,并看到UI线程正在执行代码并且没有在锁上停止。
  • 消防水带错误。当产生结果的线程比处理结果的线程消耗的速度快时,就会发生火灾。这种错误会产生各种痛苦,它看起来很像是一个僵局。最终,这样的程序在内存不足时总是会崩溃,由包含过多尚未处理结果的队列占用。顺便说一句,.NET程序具有大量可用内存。

  • 它是此程序中的3。 UI线程需要执行多项职责,并以高优先级对待调用请求。在这种情况下,分派(dispatch)调用的方法AddToQueue()。它从内部队列中读取调用请求,并在执行其他优先级较低的任务之前尝试先清空该队列。当无法清空队列时,这会出错,因为工作线程以高于UI线程可以清空队列的速率向队列添加条目。换句话说,UI线程永远无法跟上,它仅调度调用请求,而不会做任何其他事情。

    例如,在“任务管理器”中很明显,您会看到程序燃烧了100%的核心。因此,您知道这实际上并不是僵局。在用户界面中非常引人注目的是,您可以按一下“停止”按钮,但它没有任何作用。而且绘画不再发生,被视为低优先级任务,仅在没有其他重要事件发生时才执行。即使UI线程像狂暴分子一样运行,它看起来也完全冻结了。

    消防软管的错误很容易触发,每秒仅需要一千多个调用请求。取决于UI线程需要完成多少工作。通常,更新UI通常非常昂贵。设置TextBox的Text属性并不是一件很微妙的事,许多工作在幕后进行。看起来很天真的+ =运算符会消耗很多周期。除了与 native TextBox进行对话的SendMessage()的静态开销之外,持续不断的重新分配内部文本缓冲区还消耗了很多周期。比较String与StringBuilder。或者换句话说,即使您一开始不触发fire-hose错误,也可以保证早晚使用,因为TextBox包含太多的文本,需要从一个缓冲区移到另一个缓冲区。您的情况要早。

    最终,像这样的火灾软管错误是一个平衡错误。您正在更新UI的速度远远超过了人类所能观察到的速度。那不是有用的用户界面。该程序没有实际建议,它太综合了,故意减慢工作线程速度将是一种解决方法。

    关于c# - 在多线程应用中卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31228227/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com