全局静态变量使用Thread vs using Task

时间:2016-10-14 09:49:12

标签: c# multithreading winforms task

让我们说我有一个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的线程本地?

3 个答案:

答案 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服务。