全局静态变量使用线程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的线程在第二种情况?

全局静态变量使用线程vs使用任务

在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服务