какой поток для запуска кода в графическом пользовательском интерфейсе, таком как Windows Forms, WPF?

#c# #.net

Вопрос:

Я знаю, что только поток графического интерфейса может обновлять компонент пользовательского интерфейса, и для вычисления длительных задач мы должны использовать пул потоков для выполнения тяжелой работы и создания задачи продолжения для обновления пользовательского интерфейса с помощью планировщика задач контекста синхронизации.

Вот простое приложение Windows Forms

 internal sealed class MyForm : Form 
{
    private readonly TaskScheduler m_syncContextTaskScheduler;
    
    public MyForm() 
    {
        m_syncContextTaskScheduler = 
            TaskScheduler.FromCurrentSynchronizationContext();
        Text = "Synchronization Context Task Scheduler Demo";
    }

    protected override void OnMouseClick(MouseEventArgs e) 
    {
        // This task uses the default task scheduler and executes on a thread pool thread
        Task<Int32> t = Task.Run(...);
        // This task uses the sync context task scheduler and execute on the GUI thread
        t.ContinueWith(task => Text = "Result: "   task.Result, 
            CancellationToken.None, 
            TaskContinuationOptions.OnlyOnRanToCompletion, 
            m_syncContextTaskScheduler);
        ...
        base.OnMouseClick(e);
   }
}
 

Мой вопрос довольно прост: какой поток для этого запускает код, например OnMouseClick метод? Является ли сам поток графического интерфейса, выполняющий этот код, поэтому задействованы только два потока, один поток графического интерфейса и один рабочий поток? или рабочий поток запускает этот код, поэтому задействованы один поток графического интерфейса и два рабочих потока?

Ответ №1:

Обработчики для событий, созданных пользовательским интерфейсом, выполняются в потоке пользовательского интерфейса. Таким образом, в вашем коде OnMouseClick также будет выполняться поток пользовательского интерфейса. Он Task будет выполняться в потоке, определенном планировщиком (как правило, это будет поток пула потоков).

Технически, некоторый код может вызывать ваш OnMouseClick в потоке, отличном от пользовательского интерфейса, но это плохая практика, и стандартные элементы управления WinForms/WPF не будут делать такие вещи.

Также обратите внимание, что пул потоков обычно содержит более одного потока для выполнения задач.

Ответ №2:

Я провел простой тест в своем простом приложении WPF, как в моем ctor MainWindow (), так и в моем btnMouseClick (), я распечатал идентификатор потока {System.Threading.Thread.CurrentThread.ManagedThreadId} , и оба из них ставят 1, как вы можете себе представить. Так что да, поток графического интерфейса выполняет код в вашем OnMouseClick , тогда ваша новая задача находится в рабочем потоке.