全局静态变量使用线程vs使用任务
本文关键字:vs 任务 线程 静态 全局 变量 | 更新日期: 2023-09-27 18:13:00
假设我有一个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;
}
但是当我使用Task而不是Thread
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的线程在第二种情况?
在Dispose时loadingForm
为null的问题可能是由于变量未标记为volatile
,但它从更多线程中使用。在这种情况下,编译器或运行时可能决定对变量进行优化(缓存)。
所以我遵循Honza的建议(从主UI线程创建FormWithLabel)并重新设计我的代码如下:
public MainForm()
{
InitializeComponent();
FormWithLabel splash = new FormWithLabel();
//start long-term work in a separate thread
new Task(() => { DoHeavyWork(splash); }).Start();
//FormWithLabel will be closed at the end of DoHeavyWork task
splash.ShowDialog(this);
}
private void DoHeavyWork(FormWthLabel splash)
{
for (int i = 1; i <= 5; i++)
{
//checking whether FormWithHelp handle is already created to ensure
//that following Invoke will not throw InvalidOperationException
while (!lScreen.IsHandleCreated)
Thread.Sleep(50);
//changing text inside a label on FormWithLabel (assuming label is public)
splash.Invoke(new Action(() => { splash.label.Text = "Loading item №" + i; }));
//some heavy work emulation
Thread.Sleep(1000);
}
//closing FormWithLabel and continuing main thread (showing fully filled main form)
splash.Invoke(new Action(splash.Close));
}
Tasks当我们不希望应用程序线程由于密集的任务而延迟或变慢时使用。就像在javafx应用程序中,我们不能直接使用线程,如果我们想让ui免于延迟和减速,我们必须使用task。如果你想在线程执行后完成任何任务,你必须使用像taskOnComplete或onsuccess这样的监听器。这就是为什么dispose没有被调用
对于并行的多个任务,你可以使用Executor服务