Procedura: specificare criteri dell'utilità di pianificazione specifici

I criteri dell'utilità di pianificazione consentono di controllare la strategia utilizzata dall'utilità di pianificazione quando vengono gestite le attività. In questo argomento viene illustrato come utilizzare i criteri dell'utilità di pianificazione per aumentare la priorità del thread di un'attività che visualizza un indicatore di stato sulla console.

Per un esempio in cui vengono utilizzati insieme criteri dell'utilità di pianificazione personalizzati e agenti asincroni, vedere Procedura: creare agenti che utilizzano criteri dell'utilità di pianificazione specifici.

Esempio

Nell'esempio seguente vengono eseguite due attività in parallelo. La prima attività calcola l'ennesimo numero di Fibonacci. La seconda attività visualizza stampa un indicatore di stato sula console.

La prima attività utilizza la scomposizione ricorsiva per calcolare il numero Fibonacci, ovvero ogni attività crea in modo ricorsivo sottoattività per calcolare il risultato complessivo. Un'attività che utilizza la scomposizione ricorsiva potrebbe utilizzare tutte le risorse disponibili determinando pertanto una mancanza di risorse per le altre attività. In questo esempio l'attività che visualizza l'indicatore di stato potrebbe non ricevere l'accesso alle risorse di elaborazione nel tempo previsto.

Per consentire all'attività che visualizza un messaggio di stato un accesso corretto alle risorse di elaborazione, in questo esempio vengono utilizzati i passaggi descritti in Procedura: gestire un'istanza dell'utilità di pianificazione per creare un'istanza dell'utilità di pianificazione con criteri personalizzati. I criteri personalizzati specificano che per la priorità del thread deve essere utilizzata la classe con priorità più elevata.

In questo esempio vengono utilizzate le classi Concurrency::call e Concurrency::timer per visualizzare l'indicatore di stato. Queste classi dispongono di versioni dei costruttori che accettano un riferimento a un oggetto Concurrency::Scheduler che le 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 visualizza l'indicatore di stato.

Per illustrare i vantaggi dell'utilizzo di un'utilità di pianificazione con criteri personalizzati, in questo esempio l'attività complessiva viene eseguita due volte. Nell'esempio viene innanzitutto utilizzata l'utilità di pianificazione predefinita per pianificare entrambe le attività. Viene quindi utilizzata 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 l'output che segue.

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

Sebbene entrambi i set di attività producano lo stesso risultato, la versione che utilizza i criteri personalizzati consente all'attività che visualizza l'indicatore di stato di essere eseguita con una priorità maggiore in modo da presentare un comportamento più rispondente.

Compilazione del codice

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

cl.exe /EHsc scheduler-policy.cpp

Vedere anche

Attività

Procedura: creare agenti che utilizzano criteri dell'utilità di pianificazione specifici

Altre risorse

Criteri dell'utilità di pianificazione

Procedura: gestire un'istanza dell'utilità di pianificazione