Condividi tramite


Procedura: specificare criteri dell'utilità di pianificazione specifici

I criteri dell'utilità di pianificazione consentono di controllare la strategia usata dall'utilità di pianificazione quando gestisce le attività. In questo argomento viene illustrato come usare un criterio dell'utilità di pianificazione per aumentare la priorità del thread di un'attività che stampa un indicatore di stato nella console.

Per un esempio che usa criteri dell'utilità di pianificazione personalizzati insieme agli agenti asincroni, vedere Procedura: Creare agenti che usano criteri dell'utilità di pianificazione specifici.

Esempio

Nell'esempio seguente vengono eseguite due attività in parallelo. La prima attività calcola il numero n di Fibonacci. La seconda attività stampa un indicatore di stato nella console.

La prima attività usa la scomposizione ricorsiva per calcolare il numero di Fibonacci. Ovvero, ogni attività crea in modo ricorsivo sottoattività per calcolare il risultato complessivo. Un'attività che usa la scomposizione ricorsiva potrebbe usare tutte le risorse disponibili e quindi fissare altre attività. In questo esempio, l'attività che stampa l'indicatore di stato potrebbe non ricevere l'accesso tempestivo alle risorse di calcolo.

Per fornire all'attività che stampa un messaggio di stato accesso equo alle risorse di calcolo, questo esempio usa i passaggi descritti in Procedura: Gestire un'istanza dell'utilità di pianificazione per creare un'istanza dell'utilità di pianificazione con criteri personalizzati. Il criterio personalizzato specifica la priorità del thread come classe con priorità più alta.

Questo esempio usa le classi concurrency::call e concurrency::timer per stampare l'indicatore di stato. Queste classi hanno versioni dei relativi costruttori che accettano un riferimento a un oggetto concurrency::Scheduler che li pianifica. Nell'esempio viene utilizzata l'utilità di pianificazione predefinita per pianificare l'attività che calcola il numero di Fibonacci e l'istanza dell'utilità di pianificazione per pianificare l'attività che stampa l'indicatore di stato.

Per illustrare i vantaggi dell'uso di un'utilità di pianificazione con criteri personalizzati, questo esempio esegue l'attività complessiva due volte. L'esempio usa innanzitutto l'utilità di pianificazione predefinita per pianificare entrambe le attività. L'esempio usa quindi l'utilità di pianificazione predefinita per pianificare la prima attività e un'utilità di pianificazione con criteri personalizzati per pianificare la seconda attività.

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

Questo esempio produce il seguente output:

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

Sebbene entrambi i set di attività producano lo stesso risultato, la versione che usa un criterio personalizzato consente all'attività che stampa l'indicatore di stato di eseguire a una priorità elevata in modo che si comporti in modo più reattivo.

Compilazione del codice

Copiare il codice di esempio e incollarlo in un progetto di Visual Studio oppure incollarlo in un file denominato scheduler-policy.cpp e quindi eseguire il comando seguente in una finestra del prompt dei comandi di Visual Studio.

cl.exe /EHsc scheduler-policy.cpp

Vedi anche

Criteri dell'utilità di pianificazione
Procedura: Gestire un'istanza dell'utilità di pianificazione
Procedura: Creare agenti che usano criteri dell'utilità di pianificazione specifici