【问题标题】:c# cross thread errorc# 跨线程错误
【发布时间】:2018-06-05 08:30:27
【问题描述】:

我编写了一个程序来保存传感器的 3 个不同位置。如果传感器回到保存的位置,我希望我的文本框的背景颜色为绿色。因为这些值的变化非常快速和精确,所以我决定只比较前 3 个值。所以我启动了我的程序并通过单击保存了一个位置。该位置已保存,文本框立即变为绿色,这很好,因为传感器仍处于此位置。但在那之后我得到了一个跨线程的例外,我不明白。我是 C# 的新手,我认为我在函数开始时通过调用解决了这个问题。

        private void Safe_Position1(TextBox tBr1, TextBox tBi1, TextBox tBj1, TextBox tBk1, string[] text)
    {
        if (button3clicked == true)
        {
            if (!Dispatcher.CheckAccess())
            {
                textBox5.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox7.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox8.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox9.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }

            else
            {
                tBr1.Text = text[0];
                tBi1.Text = text[1];
                tBj1.Text = text[2];
                tBk1.Text = text[3];
                button3clicked = false;
            }

            string firstthreetBr1 = new string(text[0].Take(3).ToArray());
            string firstthreetBi1 = new string(text[1].Take(3).ToArray());
            string firstthreetBj1 = new string(text[2].Take(3).ToArray());
            string firstthreetBk1 = new string(text[3].Take(3).ToArray());


            if (firstthreetBr1 == tBr1.Text.Substring(0,3)) <------ EXCEPTION HERE
            {
                tBr1.Background = Brushes.Green;
            }
            if (firstthreetBi1 == tBi1.Text.Substring(0, 3))
            {
                tBi1.Background = Brushes.Green;
            }
            if (firstthreetBj1 == tBj1.Text.Substring(0, 3))
            {
                tBj1.Background = Brushes.Green;
            }
            if (firstthreetBk1 == tBk1.Text.Substring(0, 3))
            {
                tBk1.Background = Brushes.Green;
            }
        }
    }

谁能给我解释一下?

【问题讨论】:

  • 什么异常?
  • 在哪一行?
  • 安全 vs 保存 vs 安全
  • 每个BeginInvoke() 块都需要一个return,否则在调用BeginInvoke() 之后,ifs 后面的代码仍然会被执行。
  • 什么是异常信息

标签: c# multithreading exception


【解决方案1】:

我为你做了类似(不一样——你应该明白不要复制粘贴)的情况。

单击按钮时,我正在创建 3 个线程,它们正在更新文本框的文本(在 UI 线程中创建)

private void btnStart_Click(object sender, EventArgs e)
{
    Thread t1 = new Thread(() => ThreadRunner(1));
    Thread t2 = new Thread(() => ThreadRunner(2));
    Thread t3 = new Thread(() => ThreadRunner(3));
    t1.Start();
    t2.Start();
    t3.Start();
}
private void ThreadRunner(int threadNum)
{
    while(true)
    {
        TextBoxUpdater(threadNum);
        Thread.Sleep(100 * threadNum);
    }
}

以及被调用来更新文本框的方法,

private void TextBoxUpdater(int num)
{
    //here i m checking, if it is from different thread then UI thread
    //if yes then Invoke is used, 
    //      so it will call the same method but in UI thread
    if(this.InvokeRequired)
    {
        txtBox1.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox2.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox3.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();
    }

    //but after all above checks, we are leving below code without any checking
    //so once if part of this code will call this function again and else part of code runs
    // and then after completing that call, 
    //      flow will retun back to if part (not that it is not UI thread), 
    //      then flow will directly checks below codition and throw an exception
    if (txtBox1.Text.Substring(1) == "1")
    {

    }
}

您可以像下面这样进行最少的更改来防止异常。

private void TextBoxUpdater(int num)
{
    //here i m checking, if it is from different thread then UI thread
    //if yes then Invoke is used, 
    //      so it will call the same method but in UI thread
    if(this.InvokeRequired)
    {
        txtBox1.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox2.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox3.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();

        //perform this logic too insdie of else block
        if (txtBox1.Text.Substring(1) == "1")
        {
        }
    }
}

但是同样,你的方法最终会调用太多不必要的调用 TextBoxUpdater你应该想知道我为什么要这么说。

所以要修复这部分,你应该修改你的方法,如下所示。

private void TextBoxUpdater(int num)
{
    if (this.InvokeRequired)
    {
        //if current call is form other than UI thread invoke to UI thread
        this.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();
        if (txtBox1.Text.Substring(1) == "1")
        {

        }
    }
}

【讨论】:

    【解决方案2】:

    正如 Matthew 所说,您必须在每个 BeginInvoke() 之后编写 return 语句。此代码引发异常,因为在您的方法从 BeginInvoke() 返回后,它会更深入地进入代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多