방법: 특정 스케줄러 정책을 사용하는 에이전트 만들기How to: Create Agents that Use Specific Scheduler Policies

에이전트는 다른 구성 요소와 비동기 방식으로 작동 하 여 더 큰 컴퓨팅 작업을 해결 하는 응용 프로그램 구성 요소입니다.An agent is an application component that works asynchronously with other components to solve larger computing tasks. 에이전트는 일반적으로 설정 된 수명 주기를 가지 며 상태를 유지 관리 합니다.An agent typically has a set life cycle and maintains state.

모든 에이전트에는 고유한 응용 프로그램 요구 사항이 있을 수 있습니다.Every agent can have unique application requirements. 예를 들어 입력을 검색 하거나 출력을 표시 하는 사용자 상호 작용을 가능 하 게 하는 에이전트는 컴퓨팅 리소스에 대 한 우선 순위가 더 높은 액세스를 요구 합니다.For example, an agent that enables user interaction (either retrieving input or displaying output) might require higher priority access to computing resources. Scheduler 정책을 사용 하면 스케줄러에서 작업을 관리할 때 사용 하는 전략을 제어할 수 있습니다.Scheduler policies let you control the strategy that the scheduler uses when it manages tasks. 이 항목에서는 특정 스케줄러 정책을 사용 하는 에이전트를 만드는 방법을 보여 줍니다.This topic demonstrates how to create agents that use specific scheduler policies.

비동기 메시지 블록과 함께 사용자 지정 스케줄러 정책을 사용 하는 기본 예제는 방법: 특정 스케줄러 정책 지정을참조 하세요.For a basic example that uses custom scheduler policies together with asynchronous message blocks, see How to: Specify Specific Scheduler Policies.

이 항목에서는 에이전트, 메시지 블록 및 메시지 전달 함수와 같은 비동기 에이전트 라이브러리의 기능을 사용 하 여 작업을 수행 합니다.This topic uses functionality from the Asynchronous Agents Library, such as agents, message blocks, and message-passing functions, to perform work. 비동기 에이전트 라이브러리에 대 한 자세한 내용은 비동기 에이전트 라이브러리를 참조 하십시오.For more information about the Asynchronous Agents Library, see Asynchronous Agents Library.

예제Example

다음 예제에서는 concurrency:: agent: 및에서 파생 되는 두 개의 클래스를 정의 합니다. permutor printerThe following example defines two classes that derive from concurrency::agent: permutor and printer. permutor클래스는 지정 된 입력 문자열의 모든 순열을 계산 합니다.The permutor class computes all permutations of a given input string. printer클래스는 진행률 메시지를 콘솔에 출력 합니다.The printer class prints progress messages to the console. permutor클래스는 사용 가능한 모든 컴퓨팅 리소스를 사용할 수 있는 계산 집약적인 작업을 수행 합니다.The permutor class performs a computationally-intensive operation, which might use all available computing resources. 유용 하 게 사용할 수 있도록 printer 클래스는 각 진행률 메시지를 시기 적절 하 게 인쇄 해야 합니다.To be useful, the printer class must print each progress message in a timely manner.

printer클래스에 컴퓨팅 리소스에 대 한 공평 한 액세스를 제공 하기 위해이 예제에서는 방법: 스케줄러 인스턴스 관리 에 설명 된 단계를 사용 하 여 사용자 지정 정책을 포함 하는 스케줄러 인스턴스를 만듭니다.To provide the printer class fair access to computing resources, this example uses steps that are described in How to: Manage a Scheduler Instance to create a scheduler instance that has a custom policy. 사용자 지정 정책은 우선 순위가 가장 높은 클래스가 되도록 스레드 우선 순위를 지정 합니다.The custom policy specifies the thread priority to be the highest priority class.

사용자 지정 정책이 있는 스케줄러를 사용 하는 이점을 보여 주기 위해이 예에서는 전체 작업을 두 번 수행 합니다.To illustrate the benefits of using a scheduler that has a custom policy, this example performs the overall task two times. 이 예에서는 먼저 기본 스케줄러를 사용 하 여 두 작업을 예약 합니다.The example first uses the default scheduler to schedule both tasks. 그런 다음이 예제에서는 기본 스케줄러를 사용 하 여 permutor 개체를 예약 하 고, 개체를 예약 하는 사용자 지정 정책이 있는 스케줄러를 사용 합니다 printer .The example then uses the default scheduler to schedule the permutor object, and a scheduler that has a custom policy to schedule the printer object.

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

이 예제의 결과는 다음과 같습니다.This example produces the following output.

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

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

두 작업 집합 모두 동일한 결과를 생성 하지만, 사용자 지정 정책을 사용 하는 버전을 사용 하면 printer 개체가 더 반응 동작 하도록 승격 된 우선 순위로 실행 될 수 있습니다.Although both sets of tasks produce the same result, the version that uses a custom policy enables the printer object to run at an elevated priority so that it behaves more responsively.

코드 컴파일Compiling the Code

예제 코드를 복사 하 여 Visual Studio 프로젝트에 붙여넣거나 라는 파일에 붙여 넣은 permute-strings.cpp 후 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행 합니다.Copy the example code and paste it in a Visual Studio project, or paste it in a file that is named permute-strings.cpp and then run the following command in a Visual Studio Command Prompt window.

cl.exe/EHsc permute-stringscl.exe /EHsc permute-strings.cpp

참고 항목See also

스케줄러 정책Scheduler Policies
비동기 에이전트Asynchronous Agents