错误 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 线程)有帮助吗?
我在另一个 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 线程)有帮助吗?