Поделиться через


Управление несколькими потоками в управляемом коде

Если у вас есть управляемое расширение VSPackage, которое вызывает асинхронные методы или имеет операции, выполняемые в потоках пользовательского интерфейса Visual Studio, следует следовать приведенным ниже рекомендациям. Поток пользовательского интерфейса можно оставить адаптивным, так как ему не нужно ждать завершения работы над другим потоком. Вы можете сделать код более эффективным, так как у вас нет дополнительных потоков, которые занимают место в стеке, и вы можете сделать его более надежным и удобным для отладки, так как вы избегаете взаимоблокировок и неответственного кода.

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

Важно!

В следующих рекомендациях используются API в Microsoft.VisualStudio.Threading пространстве имен, в частности, JoinableTaskFactory класс. API в этом пространстве имен являются новыми в Visual Studio 2013. Экземпляр свойства можно получить JoinableTaskFactory ThreadHelper ThreadHelper.JoinableTaskFactory.

Переключение из потока пользовательского интерфейса в фоновый поток

  1. Если вы находитесь в потоке пользовательского интерфейса и хотите выполнить асинхронную работу в фоновом потоке, используйте Task.Run():

    await Task.Run(async delegate{
        // Now you're on a separate thread.
    });
    // Now you're back on the UI thread.
    
    
  2. Если вы находитесь в потоке пользовательского интерфейса и хотите синхронно блокироваться во время выполнения работы в фоновом потоке, используйте TaskScheduler свойство TaskScheduler.Default внутри Run:

    // using Microsoft.VisualStudio.Threading;
    ThreadHelper.JoinableTaskFactory.Run(async delegate {
        await TaskScheduler.Default;
        // You're now on a separate thread.
        DoSomethingSynchronous();
        await OrSomethingAsynchronous();
    });
    

Переключение с фонового потока на поток пользовательского интерфейса

  1. Если вы находитесь в фоновом потоке и хотите сделать что-то в потоке пользовательского интерфейса, используйте SwitchToMainThreadAsync:

    // Switch to main thread
    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
    

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

    Если метод фонового потока не является асинхронным и вы не можете сделать его асинхронным, вы по-прежнему можете использовать await синтаксис для переключения в поток пользовательского интерфейса путем упаковки работы с Run, как в этом примере:

    ThreadHelper.JoinableTaskFactory.Run(async delegate {
        // Switch to main thread
        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
        // Do your work on the main thread here.
    });