【问题标题】:Accessing RichTextBox in Multi-threaded application causes OutOfMemoryException在多线程应用程序中访问 RichTextBox 导致 OutOfMemoryException
【发布时间】:2015-02-06 18:36:32
【问题描述】:

我可能只是做错了。我目前正在使用 MSMQ 和 Webservices。我想了解 MSMQ 是如何工作的,所以我找到了一个贷款经纪人的学校示例。

长话短说,我需要能够对我的系统进行压力测试,所以我希望能够发送 100 条消息并通过我的消息系统发送它们。我想从 Windows 窗体应用程序中做到这一点,但问题就在这里。我有一个看起来像这样的表格:

在左侧,您会看到一个自定义控件,在右侧,我的“控制台”窗口会告诉我发生了什么。当我按下发送按钮时,它应该使用上面字段中给出的数据来发送消息。但是当我按下发送按钮时,程序会冻结一段时间,然后点击OutOfMemoryException。这是Send 方法:

private void Send(List<SimpleRequest.LoanRequest> list)
{
    int quantity = int.Parse(numericQuantity.Value.ToString());
    int delay = int.Parse(numericDelay.Value.ToString());

    if (list.Count == 1)
    {
        for (int threadnumber = 0; threadnumber < quantity; threadnumber++)
        {
            Task.Factory.StartNew(() => RequestLoanQuote(threadnumber, list[0]));
            if (delay > 0)
            {
                Thread.Sleep(delay);
            }
        }
    }
    else
    {
        for (int threadnumber = 0; threadnumber < quantity; threadnumber++)
        {
            Task.Factory.StartNew(() => RequestLoanQuote(threadnumber, list[threadnumber]));
            if (delay > 0)
            {
                Thread.Sleep(delay);
            }
        }
    }
}

这是Send 方法正在调用的RequestLoanQuote 方法:

private void RequestLoanQuote(object state, SimpleRequest.LoanRequest loanRequest)
{
    try
    {
        if (console.InvokeRequired)
        {
            SetText("Sending: " + loanRequest.SSN + "\n");
        }

        StringBuilder sb = new StringBuilder();
        var threadnumber = (int)state;
        using (var client = new LoanBrokerWS.LoanBrokerWSClient())
        {
            Utility_Tool.LoanBrokerWS.LoanQuote response = client.GetLoanQuote(loanRequest.SSN, loanRequest.LoanAmount, loanRequest.LoanDuration);
            sb.Append(response.SSNk__BackingField + " returned: ");
            sb.Append(response.interestRatek__BackingField + " | ");
            sb.Append(response.BankNamek__BackingField + "\n");
            SetText(sb.ToString());
        }
    }
    catch (Exception e)
    {
        SetText(e.Message + "\n");
    }
}

最后,SetText 方法:

private void SetText(String msg)
{
    if (this.console.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { msg });
    }
    else
    {
        this.console.Text += msg;
    }
}

所以Send 方法调用RequestLoanQuote 方法,后者调用SetText 方法。我不知道我哪里出错了,但它可能是一个僵局。

【问题讨论】:

  • this.consoleRichTextBox,对吗?尝试使用this.console.AppendText(msg)。另外,请尝试使用BeginInvoke 而不是Invoke
  • @dbc 谢谢你成功了。你想把它作为一个答案吗? :)

标签: c# multithreading winforms msmq


【解决方案1】:

尝试使用BeginInvokeAppendText,如下所示:

    public static void SetText(this RichTextBox textBox, string msg)
    {
        Action append = () => textBox.AppendText(msg);

        if (textBox.InvokeRequired)
            textBox.BeginInvoke(append);
        else
            append();
    }

【讨论】:

  • 不过有一个问题。它似乎没有按预期启动所有线程。如果我告诉它启动 10 个请求,它可能会先启动 5 个,然后再启动其他 5 个或任何随机数的剩余请求。不确定我做错了什么,或者是否由于多线程而出现这种情况。
  • @Vipar - 不是我的专业领域,但您实际上是在创建Task,对吧?我相信Task 实际上是一个非常轻量级的对象,当一个线程空闲时,它会被分配在某个线程(一个较重的对象)上运行。也许再问一个更集中的问题?
  • 我可以试试。感谢您的尝试:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
相关资源
最近更新 更多