错误 textBox3 在执行 Plinq 查询时从除创建它的线程以外的线程访问

error textBox3 ACCESSED FROM A THREAD OTHER THAN THE THREAD IT WAS CREATED ON while executing Plinq query

我在另一个 class 中有一个方法 select 所有包含来自 textbox2 的给定字符的行,并在 button_click 上将其打印到 textbox3 但我遇到了这个错误(从创建它的线程以外的线程访问 textBox3)。

public void plinq()
    {
        List<string> lines = new List<string>(textBox2.Lines);
        List<string> lines2 = new List<string>();
        try
        {
            if (textBox3.InvokeRequired)
            {
                textBox3.Invoke(new Action(plinq));
            }
            else
            {
                lines.AsParallel().ForAll(K =>
                {
                    for (int i = 0; i < K.Length; i++)
                    {
                        if (lines[i].Contains(textBox4.Text))
                        {
                            lines2.Add(lines[i]);
                        }  
                    }
                    textBox3.Lines = lines2.ToArray();
                }); 
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
        }
    }

她是我调用方法的按钮的代码

        private void button6_Click(object sender, EventArgs e)
    {
        textBox3.Text = "";
        int n = Convert.ToInt32(textBox1.Text);
        worker = new Worker(n, textBox2, textBox3, textBox4);
        Thread thread = new Thread(worker.plinq);
        sw.Start();
        thread.Start();
        //worker.plinq();
        sw.Stop();
        button6.Text = Convert.ToString(sw.Elapsed);
        sw.Reset();
    }

引用的副本已经很旧了。它并非不准确 - 但它早于 PLINQ。

看这里:

MS Documentation: Potential pitfalls with PLINQ

Avoid calls to non-thread-safe methods

Writing to non-thread-safe instance methods from a PLINQ query can lead to data corruption which may or may not go undetected in your program. It can also lead to exceptions. In the following example, multiple threads would be attempting to call the FileStream.Write method simultaneously, which is not supported by the class.

...

Prefer ForAll to ForEach when it is possible

Although PLINQ executes a query on multiple threads, if you consume the results in a foreach loop (For Each in Visual Basic), then the query results must be merged back into one thread and accessed serially by the enumerator. In some cases, this is unavoidable; however, whenever possible, use the ForAll method to enable each thread to output its own results, for example, by writing to a thread-safe collection such as System.Collections.Concurrent.ConcurrentBag.

The same issue applies to Parallel.ForEach. In other words, source.AsParallel().Where().ForAll(...) should be strongly preferred to Parallel.ForEach(source.AsParallel().Where(), ...).

...

Be aware of thread affinity issues

Some technologies, for example, COM interoperability for Single-Threaded Apartment (STA) components, Windows Forms, and Windows Presentation Foundation (WPF), impose thread affinity restrictions that require code to run on a specific thread. For example, in both Windows Forms and WPF, a control can only be accessed on the thread on which it was created. If you try to access the shared state of a Windows Forms control in a PLINQ query, an exception is raised if you are running in the debugger. (This setting can be turned off.) However, if your query is consumed on the UI thread, then you can access the control from the foreach loop that enumerates the query results because that code executes on just one thread.

...

请更新您的post:

Q1:具体错误发生在哪一行?

问题 2:它是发生在调试器中,还是发生在调试器之外,还是两者都发生?

问题 3:使用 link 中的任何建议重构您的代码是否有帮助?

Q4:是否重构您的代码,以便对 "TextBox3" 的所有修改发生在 PLinq 的 OUTSIDE 之外(并且发生在 ONLY UI 线程)有帮助吗?