Como especificar políticas de agendador específicas
As políticas do agendador permitem controlar a estratégia que o agendador usa ao gerenciar tarefas. Este tópico mostra como usar uma política de agendador para aumentar a prioridade de thread de uma tarefa que imprime um indicador de progresso no console.
Para obter um exemplo básico que usa políticas de agendador personalizadas junto com agentes assíncronos, confira Como criar agentes que usam políticas de agendador específicas.
Exemplo
O exemplo a seguir executa duas tarefas em paralelo. A primeira tarefa calcula o enésimo número de Fibonacci. A segunda tarefa imprime um indicador de progresso no console.
A primeira tarefa usa decomposição recursiva para calcular o número de Fibonacci. Ou seja, cada tarefa cria recursivamente subtarefas para calcular o resultado geral. Uma tarefa que usa a decomposição recursiva pode usar todos os recursos disponíveis e, assim, ficar desabastecida em outras tarefas. Neste exemplo, a tarefa que imprime o indicador de progresso pode não receber acesso oportuno aos recursos de computação.
Para fornecer à classe que imprime uma mensagem de progresso acesso justo aos recursos de computação, este exemplo usa as etapas descritas em Como gerenciar uma instância de agendador para criar uma instância de agendador que tenha uma política personalizada. A política personalizada especifica a prioridade do thread para ser a classe de prioridade mais alta.
Este exemplo usa as classes concurrency::call e concurrency::timer para imprimir o indicador de progresso. Essas classes têm versões de seus construtores que fazem referência a um objeto concurrency::Scheduler que as agenda. O exemplo usa o agendador padrão para agendar a tarefa que calcula o número de Fibonacci e a instância do agendador para agendar a tarefa que imprime o indicador de progresso.
Para ilustrar os benefícios de usar um agendador que tem uma política personalizada, este exemplo executa a tarefa geral duas vezes. O exemplo primeiro usa o agendador padrão para agendar ambas as tarefas. Em seguida, o exemplo usa o agendador padrão para agendar a primeira tarefa, e um agendador que tem uma política personalizada para agendar a segunda tarefa.
// 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);
}
Este exemplo gerencia a seguinte saída.
Default scheduler:
...........................................................................done
Scheduler that has a custom policy:
...........................................................................done
Embora ambos os conjuntos de tarefas produzam o mesmo resultado, a versão que usa uma política personalizada permite que a tarefa que imprime o indicador de progresso seja executada em uma prioridade elevada para que ela se comporte de modo mais responsivo.
Compilando o código
Copie o código de exemplo e cole-o em um projeto do Visual Studio, ou cole-o em um arquivo chamado scheduler-policy.cpp
e execute o comando a seguir em uma janela do Prompt de comando do Visual Studio.
cl.exe /EHsc scheduler-policy.cpp
Confira também
Políticas de agendador
Como gerenciar instâncias de agendador
Como criar agentes que usam políticas de agendador específicas