Практическое руководство. Задание определенных политик планировщика
Политики планировщика позволяют управлять стратегией, которую планировщик использует при управлении задачами. В этом разделе показано, как использовать политику планировщика для увеличения приоритета потока задачи, которая выводит индикатор хода выполнения в консоль.
Пример использования настраиваемых политик планировщика вместе с асинхронными агентами см. в разделе "Практическое руководство. Создание агентов, использующих определенные политики планировщика".
Пример
В следующем примере выполняются две задачи параллельно. Первая задача вычисляет n-й номер Fibonacci. Вторая задача выводит индикатор хода выполнения в консоль.
Первая задача использует рекурсивную декомпозицию для вычисления числа Fibonacci. То есть каждая задача рекурсивно создает подзадачи для вычисления общего результата. Задача, использующая рекурсивное декомпозиция, может использовать все доступные ресурсы и тем самым голодать другие задачи. В этом примере задача, которая печатает индикатор хода выполнения, может не получать своевременный доступ к вычислительным ресурсам.
Чтобы предоставить задачу, которая выводит сообщение о ходе выполнения, справедливый доступ к вычислительным ресурсам, в этом примере используются шаги, описанные в разделе "Практическое руководство. Управление экземпляром планировщика для создания экземпляра планировщика с настраиваемой политикой". Пользовательская политика указывает приоритет потока, который должен быть самым высоким классом приоритета.
В этом примере для печати индикатора хода выполнения используется классы параллелизма::call и параллелизма::timer . Эти классы имеют версии своих конструкторов, которые принимают ссылку на объект параллелизма::Scheduler , который планирует их. В примере используется планировщик по умолчанию для планирования задачи, вычисляющей номер Fibonacci и экземпляр планировщика, чтобы запланировать задачу, которая выводит индикатор хода выполнения.
Чтобы проиллюстрировать преимущества использования планировщика с пользовательской политикой, в этом примере выполняется общая задача в два раза. В примере сначала используется планировщик по умолчанию для планирования обоих задач. Затем в примере используется планировщик по умолчанию для планирования первой задачи и планировщика, имеющего настраиваемую политику для планирования второй задачи.
// 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);
}
В этом примере формируются следующие данные:
Default scheduler:
...........................................................................done
Scheduler that has a custom policy:
...........................................................................done
Хотя оба набора задач дают один и тот же результат, версия, которая использует пользовательскую политику, позволяет задаче, которая печатает индикатор хода выполнения при повышенном приоритете, чтобы он выполнялся более быстро.
Компиляция кода
Скопируйте пример кода и вставьте его в проект Visual Studio или вставьте его в файл с именем scheduler-policy.cpp
, а затем выполните следующую команду в окне командной строки Visual Studio.
cl.exe /EHsc scheduler-policy.cpp
См. также
Политики планировщика
Практическое руководство. Управление экземпляром планировщика
Практическое руководство. Создание агентов, использующих определенные политики планировщика