0

これは基本的にコードです:

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 が開始されると、新しいスレッドには時間がかかり、UI が完全にフリーズするため (GeneraListaCartelle()これも長い時間がかかるため、これは発生しません)、私は新しいスレッドに興味がありません。InvokeRequiredまた、 andを使用せずに UI の Controls に書き込むことができるためMethodInvokerです。

私はいくつかのポイントを逃しますか?

4

2 に答える 2

3

Task.Factory.StartNew(() => CopiaCartelle()) 次のように変更してみてください 。

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

UIスレッドの続きでGeneraListaCartelleCompletataに入り、UIスレッドでタスクをスケジュールしているようです-TaskScheduler.Defaultを配置すると、独自のスレッドで実行されます。(確認のためにこれをテストしました)

于 2013-04-18T11:06:46.320 に答える
0

@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 LooseLabel がマウスの追従を停止すると、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

さらに疑問がある場合は、お気軽にコメントしてください。

于 2013-04-18T13:25:08.183 に答える