簡體   English   中英

完成后啟動一個新線程:為什么我沒有加入新線程?

[英]Start a new Thread when one has finished: why am I not in a new Thread?

這基本上是代碼:

private void TaskGestioneCartelle()
{
    Task.Factory.StartNew(() => GeneraListaCartelle())
        .ContinueWith(t => GeneraListaCartelleCompletata()
        , CancellationToken.None
        , TaskContinuationOptions.None
        , TaskScheduler.FromCurrentSynchronizationContext());
}

private void GeneraListaCartelle()
{
    // ... code
}

private void GeneraListaCartelleCompletata()
{
    Task.Factory.StartNew(() => CopiaCartelle())
        .ContinueWith(t => CopiaCartelleCompletato()
        , CancellationToken.None
        , TaskContinuationOptions.None
        , TaskScheduler.FromCurrentSynchronizationContext());
}

private void CopiaCartelle()
{
    // long operation...
}

實際上,當CopiaCartelle啟動時,我不喜歡新的Thread,因為它要花很多時間,並且UI完全凍結(而在GeneraListaCartelle() ,它也需要很長時間,所以不會發生這種情況)。 也是因為我可以在UI中編寫控件,而無需使用InvokeRequiredMethodInvoker

我想念幾點嗎?

嘗試將Task.Factory.StartNew(() => CopiaCartelle())更改為以下內容:

Task.Factory.StartNew(() => CopiaCartelle(),  CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default))

您將繼續在UI線程上進入GeneraListaCartelleCompletata,它似乎在UI線程上調度任務-將TaskScheduler.Default放回它自己的線程中。 (只需測試一下即可確認)

@NDJ發布的內容是正確的,我舉了一個簡單的例子來說明正在發生的事情。

首先,方法是:

private static void TaskGestioneCartelle()
{            
    Task.Factory.StartNew(() => GeneraListaCartelle())
        .ContinueWith(t => GeneraListaCartelleCompletata()
        , CancellationToken.None
        , TaskContinuationOptions.None
        , TaskScheduler.FromCurrentSynchronizationContext());
}

private static void GeneraListaCartelle()
{
    //No sleep could block the thread UI because the task is being executed on a different Thread
    Debug.WriteLine("GeneraListaCartelle " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(4000);            
    mainForm.Invoke(new Action(() => bla.Text = "uno due tre, Genera Lista!"));            
}

private static void GeneraListaCartelleCompletata()
{
    //This is begin executed on the UI thread
    Debug.WriteLine("GeneraListaCartelleCompletata " + Thread.CurrentThread.ManagedThreadId);
    Task.Factory.StartNew(() => CopiaCartelle())
        .ContinueWith(t => CopiaCartelleCompletato()
        , CancellationToken.None
        , TaskContinuationOptions.None
        , TaskScheduler.FromCurrentSynchronizationContext());
}

private static void CopiaCartelle()
{
    //This is begin executed on the UI thread (doesn't even show in the form 'cause the thread is blocked)
    Debug.WriteLine("CopiaCartelle " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(4000);   
    mainForm.Invoke(new Action(() => bla.Text = "Copia Cartelle \\o"));            
}

private static void CopiaCartelleCompletato()
{
    //This is begin executed on the UI thread
    Debug.WriteLine("CopiaCartelleCompletato " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(4000);   
    mainForm.Invoke(new Action(() => bla.Text = "Completato!"));
    //Stops blocking the UI thread
}

現在的形式和組成

    static Label bla = new Label()
    {
        Text = "Mama Mia, Gestione Cartelle!",
        Left = 100,
        Top = 100,
        Width=300
    };

    static Label hangOn = new Label()
    {
        Text="Hang loose"
    };

    static Form mainForm = new Form()
    {
        Width = 600,
        Height = 600
    };

[STAThread]
static void Main(string[] args)
{
    mainForm.Controls.Add(bla);
    mainForm.Controls.Add(hangOn);
    mainForm.MouseMove += (o, e) => { hangOn.Left = e.X; hangOn.Top = e.Y; };
    Debug.WriteLine("UI Thread: "+ Thread.CurrentThread.ManagedThreadId);
    TaskGestioneCartelle();

    Application.Run(mainForm);
}

首先,運行應用程序並繼續移動鼠標。 您會注意到,鼠標懸停后,“ Hang Loose標簽”停止時,UI線程被阻止。

現在,如果您檢查“調試Output ,您將看到類似以下內容:

UI Thread: 10
GeneraListaCartelle 6
GeneraListaCartelleCompletata 10
CopiaCartelle 10
CopiaCartelleCompletato 10

看到? 它使用UI線程來運行任務,從而掛起UI。

現在,將TaskScheduler.FormCurrentSynchronizationContext()更改為TaskScheduler.Default

多田:

UI Thread: 8
GeneraListaCartelle 9
GeneraListaCartelleCompletata 10
CopiaCartelle 10
CopiaCartelleCompletato 11

注意,請注意我正在使用mainForm.Invoke調用要在UI Thread執行的動作,例如更改標簽文本。

如果您還有其他疑問,請隨時發表評論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM