Partager via


Comment : spécifier des stratégies de planificateur

Les stratégies du planificateur vous permettent de contrôler la stratégie utilisée par le planificateur lorsqu’il gère les tâches. Cette rubrique montre comment utiliser une stratégie de planificateur pour augmenter la priorité du thread d’une tâche qui imprime un indicateur de progression dans la console.

Pour obtenir un exemple qui utilise des stratégies de planificateur personnalisées avec des agents asynchrones, consultez Guide pratique pour créer des agents qui utilisent des stratégies de planificateur spécifiques.

Exemple

L’exemple suivant effectue deux tâches en parallèle. La première tâche calcule le nième nombre Fibonacci. La deuxième tâche imprime un indicateur de progression dans la console.

La première tâche utilise la décomposition récursive pour calculer le nombre Fibonacci. Autrement dit, chaque tâche crée de manière récursive des tâches secondaires pour calculer le résultat global. Une tâche qui utilise la décomposition récursive peut utiliser toutes les ressources disponibles, et donc meurent d’autres tâches. Dans cet exemple, la tâche qui imprime l’indicateur de progression peut ne pas recevoir d’accès en temps opportun aux ressources informatiques.

Pour fournir la tâche qui imprime un accès équitable aux ressources informatiques du message de progression, cet exemple utilise des étapes décrites dans How to : Manage a Scheduler Instance to create a scheduler instance that has a custom policy. La stratégie personnalisée spécifie la priorité de thread comme classe de priorité la plus élevée.

Cet exemple utilise les classes concurrency ::call et concurrency ::timer pour imprimer l’indicateur de progression. Ces classes ont des versions de leurs constructeurs qui font référence à un objet concurrency ::Scheduler qui les planifie. L’exemple utilise le planificateur par défaut pour planifier la tâche qui calcule le numéro Fibonacci et l’instance du planificateur pour planifier la tâche qui imprime l’indicateur de progression.

Pour illustrer les avantages de l’utilisation d’un planificateur qui a une stratégie personnalisée, cet exemple effectue la tâche globale deux fois. L’exemple utilise d’abord le planificateur par défaut pour planifier les deux tâches. L’exemple utilise ensuite le planificateur par défaut pour planifier la première tâche et un planificateur qui a une stratégie personnalisée pour planifier la deuxième tâche.

// 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);
}

Cet exemple produit la sortie suivante.

Default scheduler:
...........................................................................done
Scheduler that has a custom policy:
...........................................................................done

Bien que les deux ensembles de tâches produisent le même résultat, la version qui utilise une stratégie personnalisée permet à la tâche qui imprime l’indicateur de progression de s’exécuter à une priorité élevée afin qu’elle se comporte de manière plus réactive.

Compilation du code

Copiez l’exemple de code et collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé scheduler-policy.cpp , puis exécutez la commande suivante dans une fenêtre d’invite de commandes Visual Studio.

cl.exe /EHsc scheduler-policy.cpp

Voir aussi

Stratégies de planificateur
Guide pratique pour gérer une instance de planificateur
Guide pratique pour créer des agents qui utilisent des stratégies de planificateur spécifiques