让我们说我有一个FormWithLabel(只是带有标签的表格,以显示当前长期操作的状态),我会在某些情况下显示#34; heavy"在我的主申请表格中运行的任务。为此,我有静态变量:
public static FormWithLabel loadingForm = null;
我是"重"任务我在单独的线程中创建FormWithLabel并显示它直到日志操作结束。当我使用Thread时 - 它没关系:
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在" heavy"结尾处 NULL ;工作 - 所以 .Dispose()永远不会被调用。
线程和任务有什么区别?
为什么我的静态变量在第一种情况下保持全局,在第二种情况下看起来像Taks的线程本地?
答案 0 :(得分:1)
Dispose时loadingForm
为空的问题可能是由于变量未标记为volatile
这一事实引起的,但它是从更多线程使用的。在这种情况下,编译器或运行时可能决定对变量进行优化(缓存)。
答案 1 :(得分:0)
所以我按照 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));
}
答案 2 :(得分:0)
任务。 就像在javafx应用程序中我们不能直接使用线程我们必须使用任务,如果我们想要保持ui免于滞后和减速。如果要在执行线程后完成任何任务,则必须使用taskOnComplete或OnSucced等列表器。 这就是没有调用dispose的原因
对于并行的多个任务,您可以使用Executor服务。