【发布时间】:2016-04-06 14:51:29
【问题描述】:
背景
我是一个在 C# 中执行线程/并发操作的新手,并且正在为跨线程 GUI 应用程序苦苦挣扎。现在我遇到了在运行时抛出的异常,我不确定如何处理。首先,我将提供发生的背景,然后描述我尝试调试的内容。
我有一个任务要进行大量计算。
readingDumpTask = new Task(() =>
{
this.myDumpEntries = BiteDump.GetEntriesFromFile(fileName);
});
当这个任务完成后,我想同时做两件事。我通过以下方式实现了这个过程......
// display dump information
displayDumpTask = readingDumpTask.ContinueWith(
delegate
{
Parallel.Invoke
(
() => this.DisplayEntries(),
() => this.DisplayDump()
);
}
, TaskScheduler.FromCurrentSynchronizationContext());
被委托的两个方法,按以下方式工作...
方法#1
private void DisplayEntries()
{
UpdateUIDelegate myDel = new UpdateUIDelegate(this.DisplayEntries);
if (this.InvokeRequired)
{
this.BeginInvoke(myDel);
}
// fills some data into labels on the GUI
}
方法#2
private void DisplayDump()
{
UpdateUIDelegate myDel = new UpdateUIDelegate(this.DisplayDump);
if (this.InvokeRequired)
{
this.BeginInvoke(myDel);
}
// fills some data into a RTB on the GUI
}
我想明确一点,方法 #1 使用的任何控件都不会被方法 #2 触及。
问题陈述
这里的问题是,当我尝试从DisplayDump 函数内部访问控件时,我得到了InvalidOperationException。只有当我单击 Dump 选项卡时,我才会遇到此异常,如下所示。
我认为这与 DisplayDump 方法正在访问位于 Dump 选项卡内的文本框这一事实有关。现在,当我在 导航 选项卡上时,我从未遇到任何问题,并且一切正常。
尝试调试
我今天早上才发现如何查看并行任务调试窗口,更不用说真正知道如何使用它来解决我的问题了。所以,我从 Parallel.Invoke 块中删除了一个方法调用,我发现我在哪个选项卡上并不重要,在这种情况下我永远不会遇到异常 (@987654332 @ 总是有效)。但是,只要我在 Parallel 语句中执行了这两个操作,就会出现问题。所以...到目前为止,我所知道的是它与Parallel.Invoke 有关。
【问题讨论】:
-
顺便说一句,这种方法绝对没有必要使用
Parallel.Invoke,因为BeginInvoke无论如何都会在UI线程上序列化它们。 -
@IvanStoev 我不太确定,并行调用会将操作放在单独的处理器上。我自己测试过这个功能。当您说“在 UI 上对它们进行序列化”时,您听起来就像是在一个接一个地执行操作。我不想误会你,你能详细说明一下吗?
-
当方法调用
BeginInvoke时,委托在UI线程上调度。然后UI线程会一个接一个地执行调度好的委托,一次一个。 -
@IvanStoev 所以你建议把它拿出来,然后在里面有两个动作?
-
如果它们是纯 UI(如您的),是的。顺便说一句,在这种情况下,您将不需要
BeginInvoke,因为TaskScheduler.FromCurrentSynchronizationContext()将确保继续在 UI 线程上运行。
标签: c# multithreading winforms thread-safety task