방법: 특정 스케줄러 정책을 사용하는 에이전트 만들기

에이전트는 더 큰 컴퓨팅 작업을 해결하기 위해 다른 구성 요소와 비동기적으로 작동하는 애플리케이션 구성 요소입니다. 에이전트는 일반적으로 설정된 수명 주기를 가지며 상태를 기본.

모든 에이전트는 고유한 애플리케이션 요구 사항을 가질 수 있습니다. 예를 들어 사용자 상호 작용(입력 검색 또는 출력 표시)을 사용하도록 설정하는 에이전트는 컴퓨팅 리소스에 대한 우선 순위가 높은 액세스 권한이 필요할 수 있습니다. 스케줄러 정책을 사용하면 스케줄러가 작업을 관리할 때 사용하는 전략을 제어할 수 있습니다. 이 항목에서는 특정 스케줄러 정책을 사용하는 에이전트를 만드는 방법을 보여 줍니다.

사용자 지정 스케줄러 정책을 비동기 메시지 블록과 함께 사용하는 기본 예제는 방법: 특정 스케줄러 정책 지정을 참조하세요.

이 항목에서는 에이전트, 메시지 블록 및 메시지 전달 함수와 같은 비동기 에이전트 라이브러리의 기능을 사용하여 작업을 수행합니다. 비동기 에이전트 라이브러리에 대한 자세한 내용은 비동기 에이전트 라이브러리를 참조 하세요.

예시

다음 예제에서는 동시성::agentpermutor에서 파생되는 두 개의 클래스를 정의합니다printer. 클래스는 permutor 지정된 입력 문자열의 모든 순열을 계산합니다. 클래스는 printer 진행률 메시지를 콘솔에 출력합니다. 클래스는 permutor 사용 가능한 모든 컴퓨팅 리소스를 사용할 수 있는 계산 집약적 작업을 수행합니다. 유용하게 사용하려면 클래스가 printer 각 진행률 메시지를 적시에 인쇄해야 합니다.

컴퓨팅 리소스에 printer 대한 클래스의 공평한 액세스를 제공하기 위해 이 예제에서는 방법: Scheduler 인스턴스 관리에서 사용자 지정 정책이 있는 스케줄러 인스턴스를 만드는 방법에 설명된 단계를 사용합니다. 사용자 지정 정책은 스레드 우선 순위를 가장 높은 우선 순위 클래스로 지정합니다.

사용자 지정 정책이 있는 스케줄러를 사용할 경우의 이점을 설명하기 위해 이 예제에서는 전체 작업을 두 번 수행합니다. 이 예제에서는 먼저 기본 스케줄러를 사용하여 두 작업을 모두 예약합니다. 그런 다음, 기본 스케줄러를 사용하여 개체를 예약하고 개체를 permutor 예약하는 사용자 지정 정책이 있는 스케줄러를 printer 사용합니다.

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

이 예제의 결과는 다음과 같습니다.

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

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

두 작업 집합 모두 동일한 결과를 생성하지만 사용자 지정 정책을 사용하는 버전을 사용하면 개체가 더 반응적으로 동작하도록 높은 우선 순위에서 개체를 실행할 수 printer 있습니다.

코드 컴파일

예제 코드를 복사하여 Visual Studio 프로젝트에 붙여넣거나 이름이 지정된 permute-strings.cpp 파일에 붙여넣은 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행합니다.

cl.exe /EHsc permute-strings.cpp

참고 항목

스케줄러 정책
비동기 에이전트