【发布时间】:2016-10-14 09:49:11
【问题描述】:
假设我有一个 FormWithLabel(只是带有标签的表单以显示当前长期操作的状态),我会在我的主应用程序表单中运行一些“繁重”任务时显示它。为此,我有静态变量:
public static FormWithLabel loadingForm = null;
在“繁重”任务的情况下,我在单独的线程中创建 FormWithLabel 并显示它,直到日志操作结束。当我使用线程时 - 没关系:
Thread loadingFormThread = new Thread(new ThreadStart(() =>
{
loadingForm = new FormWithLabel();
loadingForm.ShowDialog();
}
));
loadingFormThread.SetApartmentState(ApartmentState.STA);
loadingFormThread.Start();
...
//some "heavy" work which is done separate thread and updates some visual data in main UI via Invoke()
...
if (loadingForm != null)
{
loadingForm.Dispose();
loadingForm = null;
}
但是当我使用任务而不是线程时
new Task(() =>
{
loadingForm = new FormWithLabel();
loadingForm.ShowDialog();
}).Start();
...
//some "heavy" work which is done separate thread and updates some visual data in main UI via Invoke()
...
if (loadingForm != null)
{
loadingForm.Dispose();
loadingForm = null;
}
loadingForm 在“繁重”工作结束时为 NULL - 因此永远不会调用 .Dispose()。
线程和任务有什么区别?
为什么我的静态变量在第一种情况下保持全局,而在第二种情况下对于 Taks 的线程来说似乎是本地的?
【问题讨论】:
-
你几乎违反了书中的每一条规则。该任务只会使情况变得更糟,它不是 STA。仅当您 understand how to do this 时才这样做。以正确的方式执行此操作,“繁重的工作”必须在工作线程上完成,始终保持 UI 线程可用于显示和更新 UI。
-
大部分方法 witt Thread 都是从 Telerik sample 复制而来的
-
启动画面通常是很无辜的,它们只是显示一个位图并且不使用使用 SystemEvents 类的控件。喜欢标签。随意省略关闭窗口的 Invoke() 调用也是一个重大错误。像这样的线程错误非常难以调试。不要这样做。
-
好吧,让我们想象一下我的 FormWithLabel 里面只有一个图片框。我的问题中描述的行为有什么变化?线程仍然可以正常工作,但任务 - 不是......而且顺便说一句 - 你在我上面的代码示例中哪里看到 Invoke() 调用?
-
更好的方法是从主 UI 线程(无任务或线程)创建您的
FormWithLabel,然后使用任务或线程来完成繁重的工作,并且可以使用Invoke从你的繁重工作。
标签: c# multithreading winforms task