Udostępnij za pośrednictwem


Jak: tworzenie czynników, które używają zasad szczególnych harmonogram

Agent jest składnikiem aplikacji, który działa asynchronicznie, z innymi składnikami, aby rozwiązać większych zadań wykonywanych.Agent zazwyczaj ma set cyklu życia i zachowuje stan.

Każdy agent może mieć unikatowych wymagań.Na przykład agenta, który umożliwia interakcji z użytkownikiem (pobieranie wprowadzania lub wyświetlania danych wyjściowych) mogą wymagać wyższych priorytetowy dostęp do zasobów komputerowych.Harmonogram zasady pozwalają określić strategii, która używa harmonogramu, podczas zarządzania zadaniami.W tym temacie przedstawia sposób tworzenia czynników, które używają zasad szczególnych harmonogramu.

Prosty przykład używa niestandardowy harmonogram zasady wraz z bloków komunikatów asynchronicznych, zobacz Jak: określić szczególne zasady harmonogram.

W tym temacie korzysta z funkcji z biblioteki asynchronicznego czynników, takich jak agentów, bloki komunikatów i funkcje służące do przekazywania wiadomości, do wykonywania pracy.Więcej informacji o asynchronicznych biblioteki agentów, zobacz Biblioteka agentów asynchroniczne.

Przykład

Poniższy przykład definiuje dwie klasy, które wynikają z concurrency::agent: permutor i printer.permutor Klasy oblicza wszystkie permutacji danego ciągu wejściowego.printer Klasy drukuje komunikaty postępu w konsoli.permutor Klasy wykonuje operację intensywnie obliczeniowo, którego może używać wszystkich dostępnych zasobów komputerowych.Użyteczne, printer klasy należy wydrukować każdy komunikat postępu w sposób terminowy.

Zapewnienie printer klasy sprawiedliwy dostęp do zasobów komputerowych, w tym przykładzie użyto kroków opisanych w Jak: Zarządzanie wystąpienie harmonogram do tworzenia instancji harmonogramu, która ma zasadę niestandardową.Niestandardowe zasady określa priorytet wątku za najwyższy priorytet.

Aby zilustrować korzyści wynikających z używania harmonogramu, który ma niestandardowe zasady, w tym przykładzie wykonuje zadanie ogólnej dwa razy.Harmonogram domyślny przykładzie najpierw do zaplanowania obu zadań.W przykładzie użyto następnie harmonogram domyślny do zaplanowania permutor obiektu i harmonogramu, która ma zasadę niestandardową, aby zaplanować printer obiektu.

// permute-strings.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <agents.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

// Computes all permutations of a given input string.
class permutor : public agent
{
public:
   explicit permutor(ISource<wstring>& source,
      ITarget<unsigned int>& progress)
      : _source(source)
      , _progress(progress)
   {
   }

   explicit permutor(ISource<wstring>& source,
      ITarget<unsigned int>& progress,
      Scheduler& scheduler)
      : agent(scheduler)
      , _source(source)
      , _progress(progress)
   {
   }

   explicit permutor(ISource<wstring>& source,
      ITarget<unsigned int>& progress,
      ScheduleGroup& group)
      : agent(group)       
      , _source(source)
      , _progress(progress)
   {
   }

protected:
   // Performs the work of the agent.
   void run()
   {
      // Read the source string from the buffer.
      wstring s = receive(_source);

      // Compute all permutations.
      permute(s);

      // Set the status of the agent to agent_done.
      done();
   }

   // Computes the factorial of the given value.
   unsigned int factorial(unsigned int n)
   {
      if (n == 0)
         return 0;
      if (n == 1)
         return 1;
      return n * factorial(n - 1);
   }

   // Computes the nth permutation of the given wstring.
   wstring permutation(int n, const wstring& s) 
   {
      wstring t(s);

      size_t len = t.length();
      for (unsigned int i = 2; i < len; ++i)
      {
         swap(t[n % i], t[i]);
         n = n / i;
      }
      return t;
   }

   // Computes all permutations of the given string.
   void permute(const wstring& s)
   {      
      // The factorial gives us the number of permutations.
      unsigned int permutation_count = factorial(s.length());

      // The number of computed permutations.
      LONG count = 0L;      

      // Tracks the previous percentage so that we only send the percentage
      // when it changes.
      unsigned int previous_percent = 0u;

      // Send initial progress message.
      send(_progress, previous_percent);

      // Compute all permutations in parallel.
      parallel_for (0u, permutation_count, [&](unsigned int i) {
         // Compute the permutation.
         permutation(i, s);

         // Send the updated status to the progress reader.
         unsigned int percent = 100 * InterlockedIncrement(&count) / permutation_count;
         if (percent > previous_percent)
         {
             send(_progress, percent);
             previous_percent = percent;
         }
      });

      // Send final progress message.
      send(_progress, 100u);
   }

private:
   // The buffer that contains the source string to permute.
   ISource<wstring>& _source;

   // The buffer to write progress status to.
   ITarget<unsigned int>& _progress;
};

// Prints progress messages to the console.
class printer : public agent
{
public:
   explicit printer(ISource<wstring>& source,
      ISource<unsigned int>& progress)
      : _source(source)
      , _progress(progress)
   {
   }

   explicit printer(ISource<wstring>& source,
      ISource<unsigned int>& progress, Scheduler& scheduler)
      : agent(scheduler)
      , _source(source)
      , _progress(progress)
   {
   }

   explicit printer(ISource<wstring>& source,
      ISource<unsigned int>& progress, ScheduleGroup& group)
      : agent(group)       
      , _source(source)
      , _progress(progress)
   {
   }

protected:
   // Performs the work of the agent.
   void run()
   {
      // Read the source string from the buffer and print a message.
      wstringstream ss;
      ss << L"Computing all permutations of '" << receive(_source) << L"'..." << endl;
      wcout << ss.str();

      // Print each progress message.
      unsigned int previous_progress = 0u;
      while (true)
      {         
         unsigned int progress = receive(_progress);

         if (progress > previous_progress || progress == 0u)
         { 
            wstringstream ss;
            ss << L'\r' << progress << L"% complete...";
            wcout << ss.str();
            previous_progress = progress;
         }

         if (progress == 100)
            break;
      }
      wcout << endl;

      // Set the status of the agent to agent_done.
      done();
   }

private:
   // The buffer that contains the source string to permute.
   ISource<wstring>& _source;

   // The buffer that contains progress status.
   ISource<unsigned int>& _progress;
};

// Computes all permutations of the given string. 
void permute_string(const wstring& source,
   Scheduler& permutor_scheduler, Scheduler& printer_scheduler)
{  
   // Message buffer that contains the source string.
   // The permutor and printer agents both read from this buffer.
   single_assignment<wstring> source_string;

   // Message buffer that contains the progress status.
   // The permutor agent writes to this buffer and the printer agent reads
   // from this buffer.
   unbounded_buffer<unsigned int> progress;

   // Create the agents with the appropriate schedulers.
   permutor agent1(source_string, progress, permutor_scheduler);
   printer agent2(source_string, progress, printer_scheduler);

   // Start the agents.
   agent1.start();
   agent2.start();

   // Write the source string to the message buffer. This will unblock the agents.
   send(source_string, source);

   // Wait for both agents to finish.
   agent::wait(&agent1);
   agent::wait(&agent2);
}

int wmain()
{
   const wstring source(L"Grapefruit");

   // Compute all permutations on the default scheduler.

   Scheduler* default_scheduler = CurrentScheduler::Get();

   wcout << L"With default scheduler: " << endl;
   permute_string(source, *default_scheduler, *default_scheduler);
   wcout << endl;

   // Compute all permutations again. This time, provide a scheduler that
   // has higher context priority to the printer agent.

   SchedulerPolicy printer_policy(1, ContextPriority, THREAD_PRIORITY_HIGHEST);
   Scheduler* printer_scheduler = Scheduler::Create(printer_policy);

   // Register to be notified when the scheduler shuts down.
   HANDLE hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   printer_scheduler->RegisterShutdownEvent(hShutdownEvent);

   wcout << L"With higher context priority: " << endl;
   permute_string(source, *default_scheduler, *printer_scheduler);
   wcout << endl; 

   // Release the printer scheduler.
   printer_scheduler->Release();

   // Wait for the scheduler to shut down and destroy itself.
   WaitForSingleObject(hShutdownEvent, INFINITE);

   // Close the event handle.
   CloseHandle(hShutdownEvent);
}

Ten przykład generuje następujące wyniki.

With default scheduler:
Computing all permutations of 'Grapefruit'...
100% complete...

With higher context priority:
Computing all permutations of 'Grapefruit'...
100% complete...

Chociaż oba zestawy zadań daje ten sam wynik, wersji, która używa niestandardowych zasad umożliwia printer obiektu uruchamiane przy podwyższonym poziomie priorytetu, tak aby zachowuje się bardziej responsively.

Kompilowanie kodu

Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie ich uporządkowania strings.cpp , a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi programu Visual Studio.

cl.exe /EHsc permute-strings.cpp

Zobacz też

Informacje

How-to: Specify Specific Scheduler Policies

Koncepcje

Harmonogram zasady

Agenci asynchroniczne