Практическое руководство. Задание определенных политик планировщика
Политики планировщика позволяют управлять стратегией, которую планировщик использует при управлении задачами. В этом разделе показано, как использовать политику планировщика для повышения приоритета потока задачи, выводящей на консоль индикатор хода выполнения.
Пример использования пользовательской политики планировщика совместно с асинхронными агентами см. в разделе Практическое руководство. Создание агентов, использующих определенные политики планировщика.
Пример
В следующем примере параллельно выполняются две задачи. Первая задача вычисляет элемент последовательности Фибоначчи с индексом n. Вторая задача выводит индикатор хода выполнения на консоль.
В первой задаче для вычисления числа Фибоначчи используется рекурсивная декомпозиция. То есть, для вычисления общего результата каждая задача рекурсивно создает подзадачи. Задача, использующая рекурсивную декомпозицию, может занять все доступные ресурсы, которые станут недоступны другим задачам. В данном примере задача, выводящая индикатор хода выполнения, может не получить своевременный доступ к вычислительным ресурсам.
Чтобы обеспечить задаче, выводящей сообщение о ходе выполнения, адекватный доступ к вычислительным ресурсам, в данном примере с помощью шагов, описанных в разделе Практическое руководство. Управление экземпляром планировщика, создается экземпляр планировщика с пользовательской политикой. Пользовательская политика задает, что поток имеет наивысший класс приоритета.
В этом примере для вывода индикатора хода выполнения используются классы Concurrency::call и Concurrency::timer. Эти классы имеют варианты конструкторов, принимающие ссылку на объект Concurrency::Scheduler, который планирует их работу. В примере используется планировщик по умолчанию для планирования задачи, вычисляющей число Фибоначчи, и экземпляр планировщика для планирования задачи, выводящей индикатор хода выполнения.
Для демонстрации преимуществ использования планировщика с пользовательской политикой в этом примере вся задача выполняется дважды. Сначала для планирования обеих задач используется планировщик по умолчанию. Затем в примере используется планировщик по умолчанию для планирования первой задачи и планировщик с пользовательской политикой для планирования второй задачи.
// scheduler-policy.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <agents.h>
#include <iostream>
using namespace concurrency;
using namespace std;
// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
if (n < 2)
return n;
// Compute the components in parallel.
int n1, n2;
parallel_invoke(
[n,&n1] { n1 = fibonacci(n-1); },
[n,&n2] { n2 = fibonacci(n-2); }
);
return n1 + n2;
}
// Prints a progress indicator while computing the nth Fibonacci number.
void fibonacci_with_progress(Scheduler& progress_scheduler, int n)
{
// Use a task group to compute the Fibonacci number.
// The tasks in this group are scheduled by the current scheduler.
structured_task_group tasks;
auto task = make_task([n] {
fibonacci(n);
});
tasks.run(task);
// Create a call object that prints its input to the console.
// This example uses the provided scheduler to schedule the
// task that the call object performs.
call<wchar_t> c(progress_scheduler, [](wchar_t c) {
wcout << c;
});
// Connect the call object to a timer object. The timer object
// sends a progress message to the call object every 100 ms.
// This example also uses the provided scheduler to schedule the
// task that the timer object performs.
timer<wchar_t> t(progress_scheduler, 100, L'.', &c, true);
t.start();
// Wait for the task that computes the Fibonacci number to finish.
tasks.wait();
// Stop the timer.
t.stop();
wcout << L"done" << endl;
}
int wmain()
{
// Calculate the 38th Fibonacci number.
const int n = 38;
// Use the default scheduler to schedule the progress indicator while
// the Fibonacci number is calculated in the background.
wcout << L"Default scheduler:" << endl;
fibonacci_with_progress(*CurrentScheduler::Get(), n);
// Now use a scheduler that has a custom policy for the progress indicator.
// The custom policy specifies the thread priority to the highest
// priority class.
SchedulerPolicy policy(1, ContextPriority, THREAD_PRIORITY_HIGHEST);
Scheduler* scheduler = Scheduler::Create(policy);
// Register to be notified when the scheduler shuts down.
HANDLE hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
scheduler->RegisterShutdownEvent(hShutdownEvent);
wcout << L"Scheduler that has a custom policy:" << endl;
fibonacci_with_progress(*scheduler, n);
// Release the final reference to the scheduler. This causes the scheduler
// to shut down.
scheduler->Release();
// Wait for the scheduler to shut down and destroy itself.
WaitForSingleObject(hShutdownEvent, INFINITE);
// Close the event handle.
CloseHandle(hShutdownEvent);
}
В результате выполнения примера получается следующий результат:
Хотя оба набора задач дают одинаковый результат, версия, в которой используется пользовательская политика, позволяет задаче, выводящей индикатор хода выполнения, выполняться с повышенными приоритетом, обеспечивая более отзывчивое поведение.
Компиляция кода
Скопируйте пример кода и вставьте его в проект Visual Studio или файл с именем scheduler-policy.cpp, затем выполните в окне командной строки следующую команду.
cl.exe /EHsc scheduler-policy.cpp
См. также
Задачи
Практическое руководство. Управление экземпляром планировщика
Практическое руководство. Создание агентов, использующих определенные политики планировщика