다음을 통해 공유


연습: 미래 구현

이 항목에서는 응용 프로그램에서 미래를 구현하는 방법을 보여 줍니다. 여기에서는 동시성 런타임의 기존 기능을 결합하여 더 많은 작업을 수행하는 방법을 보여 줍니다.

작업은 좀 더 세분화된 추가 계산으로 분해할 수 있는 계산입니다. 미래는 나중에 사용할 수 있도록 값을 계산하는 비동기적 작업입니다.

미래를 구현하기 위해 이 항목에서는 async_future 클래스를 정의합니다. async_future 클래스는 동시성 런타임의 Concurrency::task_group 클래스와 Concurrency::single_assignment 클래스와 같은 구성 요소를 사용합니다. async_future 클래스는 task_group 클래스를 사용하여 값을 비동기적으로 계산하고 single_assignment 클래스를 사용하여 계산 결과를 저장합니다. async_future 클래스의 생성자는 결과를 계산하는 작업 함수를 사용하고 get 메서드는 결과를 검색합니다.

future 클래스를 구현하려면

  1. 결과 계산의 형식에 대해 매개 변수가 있는 async_future 템플릿 클래스를 선언합니다. public 및 private 섹션을 이 클래스에 추가합니다.

    template <typename T>
    class async_future
    {
    public:
    private:
    };
    
  2. async_future 클래스의 private 섹션에서 task_groupsingle_assignment 데이터 멤버를 선언합니다.

    // Executes the asynchronous work function.
    task_group _tasks;
    
    // Stores the result of the asynchronous work function.
    single_assignment<T> _value;
    
  3. async_future 클래스의 public 섹션에서 생성자를 구현합니다. 생성자는 결과를 계산하는 작업 함수에 대한 매개 변수가 있는 템플릿입니다. 생성자는 task_group 데이터 멤버의 작업 함수를 비동기적으로 실행하고 Concurrency::send 함수를 사용하여 single_assignment 데이터 멤버에 결과를 씁니다.

    template <class Functor>
    explicit async_future(Functor&& fn)
    {
       // Execute the work function in a task group and send the result
       // to the single_assignment object.
       _tasks.run([fn, this]() {
          send(_value, fn());
        });
    }
    
  4. async_future 클래스의 public 섹션에서 소멸자를 구현합니다. 소멸자는 작업이 끝날 때까지 기다립니다.

    ~async_future()
    {
       // Wait for the task to finish.
       _tasks.wait();
    }
    
  5. async_future 클래스의 public 섹션에서 get 메서드를 구현합니다. 이 메서드는 Concurrency::receive 함수를 사용하여 작업 함수의 결과를 검색합니다.

    // Retrieves the result of the work function.
    // This method blocks if the async_future object is still 
    // computing the value.
    T get()
    { 
       return receive(_value); 
    }
    

예제

설명

다음 예제에서는 전체 async_future 클래스 및 이 클래스의 사용법을 보여 줍니다. wmain 함수는 임의의 정수 값이 10,000개 포함된 std::vector 개체를 만듭니다. 그런 다음 async_future 개체를 사용하여 vector 개체에 포함된 값 중에서 가장 작은 값과 가장 큰 값을 찾습니다.

코드

// futures.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>

using namespace Concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still 
   // computing the value.
   T get()
   { 
      return receive(_value); 
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // Create a vector of 10000 integers, where each element 
   // is between 0 and 9999.
   mt19937 gen(2);
   vector<int> values(10000);   
   generate(values.begin(), values.end(), [&gen]{ return gen()%10000; });

   // Create a async_future object that finds the smallest value in the
   // vector.
   async_future<int> min_value([&]() -> int { 
      int smallest = INT_MAX;
      for_each(values.begin(), values.end(), [&](int value) {
         if (value < smallest)
         {
            smallest = value;
         }
      });
      return smallest;
   });

   // Create a async_future object that finds the largest value in the
   // vector.
   async_future<int> max_value([&]() -> int { 
      int largest = INT_MIN;
      for_each(values.begin(), values.end(), [&](int value) {
         if (value > largest)
         {
            largest = value;
         } 
      });
      return largest;
   });

   // Calculate the average value of the vector while the async_future objects
   // work in the background.
   int sum = accumulate(values.begin(), values.end(), 0);
   int average = sum / values.size();

   // Print the smallest, largest, and average values.
   wcout << L"smallest: " << min_value.get() << endl
         << L"largest:  " << max_value.get() << endl
         << L"average:  " << average << endl;
}

참고

이 예제는 다음과 같이 출력됩니다.

smallest: 0
largest:  9999
average:  4981

이 예제에서는 async_future::get 메서드를 사용하여 계산 결과를 검색합니다. async_future::get 메서드는 계산이 아직 활성 상태인 경우 끝날 때까지 기다립니다.

강력한 프로그래밍

작업 함수에서 throw되는 예외를 처리하도록 async_future 클래스를 확장하려면 Concurrency::task_group::wait 메서드를 호출하도록 async_future::get 메서드를 수정합니다. task_group::wait 메서드는 작업 함수에 의해 생성된 예외를 throw합니다.

다음 예제에서는 async_future 클래스의 수정된 버전을 보여 줍니다. wmain 함수는 try-catch 블록을 사용하여 async_future 개체의 결과를 인쇄하거나, 작업 함수에서 생성되는 예외의 값을 인쇄합니다.

// futures-with-eh.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace Concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still
   // computing the value.
   T get()
   { 
      // Wait for the task to finish.
      // The wait method throws any exceptions that were generated
      // by the work function.
      _tasks.wait();

      // Return the result of the computation.
      return receive(_value);
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // For illustration, create a async_future with a work 
   // function that throws an exception.
   async_future<int> f([]() -> int { 
      throw exception("error");
   });

   // Try to read from the async_future object. 
   try
   {
      int value = f.get();
      wcout << L"f contains value: " << value << endl;
   }
   catch (const exception& e)
   {
      wcout << L"caught exception: " << e.what() << endl;
   }
}

이 예제는 다음과 같이 출력됩니다.

caught exception: error

동시성 런타임의 예외 처리 모델에 대한 자세한 내용은 동시성 런타임에서 예외 처리를 참조하십시오.

코드 컴파일

예제 코드를 복사하여 Visual Studio 프로젝트 또는 futures.cpp 파일에 붙여넣고 Visual Studio 2010 명령 프롬프트 창에서 다음 명령을 실행합니다.

cl.exe /EHsc futures.cpp

참고 항목

참조

task_group 클래스

single_assignment 클래스

개념

동시성 런타임에서 예외 처리

기타 리소스

비동기 에이전트 방법 및 연습 항목