Partilhar via


Como: Especificar políticas específicas do agendador

As políticas do Agendador permitem controlar a estratégia que o agendador usa quando gerencia tarefas. Este tópico mostra como usar uma política de escalonamento para aumentar a prioridade de um thread numa tarefa que imprime um indicador de progresso no console.

Para obter um exemplo que usa políticas de agendador personalizadas junto com agentes assíncronos, consulte Como criar agentes que usam políticas específicas do agendador.

Exemplo

O exemplo a seguir executa duas tarefas em paralelo. A primeira tarefa calcula o né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 subtarefas recursivamente para calcular o resultado geral. Uma tarefa que usa decomposição recursiva pode usar todos os recursos disponíveis e, assim, esgotar 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 à tarefa 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 do Agendador para criar uma instância do Agendador que tenha uma política personalizada. A política personalizada especifica que a prioridade de thread deve ser da classe de prioridade mais elevada.

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 tenha 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. 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 produz o seguinte resultado.

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 com uma prioridade elevada para que se comporte de forma mais responsiva.

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, em seguida, execute o seguinte comando em uma janela do prompt de comando do Visual Studio.

cl.exe /EHsc scheduler-policy.cpp

Ver também

Políticas do Scheduler
Como gerenciar uma instância do Scheduler
Como criar agentes que usam políticas específicas de agendamento