Share via


병렬 컨테이너 및 개체

PPL(병렬 패턴 라이브러리)에는 스레드로부터 안전한 방식으로 요소에 액세스할 수 있도록 하는 몇 가지 컨테이너 및 개체가 포함되어 있습니다.

동시 컨테이너를 사용하면 가장 중요한 작업에 동시성이 보장된 방식으로 액세스할 수 있습니다. 이러한 컨테이너의 기능은 STL(표준 템플릿 라이브러리)에서 제공하는 컨테이너와 유사합니다. 예를 들어 Concurrency::concurrent_vector 클래스는 std::vector 클래스와 유사하지만 concurrent_vector 클래스를 사용하면 요소를 병렬로 추가할 수 있다는 점이 다릅니다. 같은 컨테이너에 읽기 및 쓰기 권한이 둘 다 필요한 병렬 코드가 있는 경우 동시 컨테이너를 사용하십시오.

동시 개체는 구성 요소 사이에서 동시에 공유됩니다. 동시 개체의 상태를 병렬로 계산하는 프로세스는 같은 상태를 순차적으로 계산하는 다른 프로세스와 같은 결과가 나타납니다. Concurrency::combinable 클래스는 동시 개체 형식의 한 예입니다. combinable 클래스를 사용하면 계산을 병렬로 수행한 다음, 이러한 계산을 최종 결과로 결합할 수 있습니다. 뮤텍스와 같은 동기화 메커니즘을 사용하여 공유 변수 또는 리소스에 대한 액세스를 동기화해야 하는 경우 동시 개체를 사용하십시오.

단원

이 항목에서는 다음과 같은 병렬 컨테이너 및 개체에 대해 자세히 설명합니다.

동시 컨테이너

  • concurrent_vector 클래스

  • concurrent_queue 클래스

동시 개체

  • combinable 클래스

concurrent_vector 클래스

Concurrency::concurrent_vector 클래스는 std::vector 클래스와 마찬가지로 요소에 임의로 액세스할 수 있는 시퀀스 컨테이너 클래스입니다. concurrent_vector 클래스를 사용하면 동시성이 보장된 방식으로 추가 및 요소 액세스 작업을 수행할 수 있습니다. 추가 작업은 기존 포인터 또는 반복기를 무효화하지 않습니다. 반복기 액세스 및 트래버스 작업도 동시성이 보장됩니다.

concurrent_vector와 vector의 차이

concurrent_vector 클래스는 vector 클래스와 매우 유사합니다. concurrent_vector 개체에 대한 추가, 요소 액세스 및 반복기 액세스 작업의 복잡성은 vector 개체의 경우와 동일합니다. 다음은 concurrent_vectorvector와 다른 점에 대한 설명입니다.

  • concurrent_vector 개체에 대한 추가, 요소 액세스, 반복기 액세스 및 반복기 트래버스 작업은 동시성이 보장됩니다.

  • concurrent_vector 개체의 끝에만 요소를 추가할 수 있습니다. concurrent_vector 클래스는 insert 메서드를 제공하지 않습니다.

  • concurrent_vector 개체에 추가하는 경우 이 개체에는 의미 체계 이동이 사용되지 않습니다.

  • concurrent_vector 클래스는 erase 또는 pop_back 메서드를 제공하지 않습니다. vector와 마찬가지로 clear 메서드를 사용하여 concurrent_vector 개체에서 모든 요소를 제거합니다.

  • concurrent_vector 클래스는 요소를 메모리에 연속적으로 저장하지 않습니다. 따라서 배열을 사용할 수 있는 모든 방법으로 concurrent_vector 클래스를 사용할 수 없습니다. 예를 들어 concurrent_vector 형식의 v라는 변수가 있는 경우 &v[0]+2 식을 실행하면 정의되지 않은 동작이 발생합니다.

  • concurrent_vector 클래스는 grow_bygrow_to_at_least 메서드를 정의합니다. 이러한 메서드는 동시성이 보장된다는 점을 제외하면 resize 메서드와 유사합니다.

  • concurrent_vector 개체는 추가하거나 크기를 조정할 때 해당 요소를 재배치하지 않습니다. 이렇게 하면 기존 포인터 및 반복기에서 동시 작업 중에 유효한 상태를 유지할 수 있습니다.

  • 런타임에서는 bool 형식에 대한 특수화된 버전의 concurrent_vector를 정의하지 않습니다.

동시성 보장 작업

concurrent_vector 개체에 추가하거나 개체의 크기를 증가시키고 concurrent_vector 개체의 요소에 액세스하는 모든 메서드는 동시성이 보장됩니다. 이 규칙이 적용되지 않는 메서드는 resize뿐입니다.

다음 표에서는 동시성이 보장되는 일반적인 concurrent_vector 메서드와 연산자를 보여 줍니다.

at

end

operator[]

begin

front

push_back

back

grow_by

rbegin

capacity

grow_to_at_least

rend

empty

max_size

size

reserve와 같이 STL과의 호환성을 위해 런타임에서 제공하는 작업은 동시성이 보장되지 않습니다. 다음 표에서는 동시성이 보장되지 않는 일반적인 메서드와 연산자를 보여 줍니다.

assign

reserve

clear

resize

operator=

shrink_to_fit

기존 요소의 값을 수정하는 작업은 동시성이 보장되지 않습니다. 같은 데이터 요소에 대한 동시 읽기 및 쓰기 권한을 동기화하려면 reader_writer_lock 개체와 같은 동기화 개체를 사용합니다. 동기화 개체에 대한 자세한 내용은 동기화 데이터 구조를 참조하십시오.

vector를 사용하는 기존 코드를 concurrent_vector를 사용하도록 변환하는 경우 동시 작업을 수행하면 응용 프로그램의 동작이 변경될 수 있습니다. 예를 들어 concurrent_vector 개체에 대해 동시에 두 작업을 수행하는 다음 프로그램을 가정해 봅니다. 첫 번째 작업은 concurrent_vector 개체에 요소를 추가합니다. 두 번째 작업은 동일한 개체에 있는 모든 요소의 합계를 계산합니다.

// parallel-vector-sum.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_vector.h>
#include <iostream>

using namespace Concurrency;
using namespace std;

int wmain()
{
   // Create a concurrent_vector object that contains a few
   // initial elements.
   concurrent_vector<int> v;
   v.push_back(2);
   v.push_back(3);
   v.push_back(4);

   // Perform two tasks in parallel.
   // The first task appends additional elements to the concurrent_vector object.
   // The second task computes the sum of all elements in the same object.

   parallel_invoke(
      [&v] { 
         for(int i = 0; i < 10000; ++i)
         {
            v.push_back(i);
         }
      },
      [&v] {
         combinable<int> sums;
         for(auto i = v.begin(); i != v.end(); ++i) 
         {
            sums.local() += *i;
         }     
         wcout << L"sum = " << sums.combine(plus<int>()) << endl;
      }
   );
}

end 메서드는 동시성이 보장되지만 push_back 메서드에 대한 동시 호출 결과 end에서 반환되는 값이 변경됩니다. 반복기에서 트래버스하는 요소의 수가 결정되지 않습니다. 따라서 이 프로그램을 실행할 때마다 다른 결과가 생성될 수 있습니다.

예외 안전성

증가 또는 할당 작업에서 예외가 throw되면 concurrent_vector 개체의 상태가 유효하지 않게 됩니다. 상태가 유효하지 않은 concurrent_vector 개체의 동작은 별도로 지정된 경우가 아니면 정의되지 않습니다. 그러나 소멸자는 개체의 상태가 유효하지 않더라도 해당 개체에서 할당하는 메모리를 항상 해제합니다.

벡터 요소 _Ty의 데이터 형식은 다음과 같은 요구 사항을 충족시켜야 합니다. 그렇지 않으면 concurrent_vector 클래스의 동작이 정의되지 않습니다.

  • 소멸자는 throw하지 않아야 합니다.

  • 기본 또는 복사 생성자에서 throw하는 경우 소멸자는 virtual 키워드를 사용하여 선언되지 않아야 하며 0으로 초기화된 메모리에서 올바르게 동작해야 합니다.

[맨 위로 이동]

concurrent_queue 클래스

Concurrency::concurrent_queue 클래스를 사용하면 std::queue 클래스와 마찬가지로 앞/뒤 요소에 액세스할 수 있습니다. concurrent_queue 클래스를 사용하면 동시성이 보장된 방식으로 큐에 대기시키거나 큐에서 제거하는 작업을 수행할 수 있습니다. 또한 concurrent_queue 클래스는 동시성이 보장되지 않는 반복기 지원도 제공합니다.

concurrent_queue와 queue의 차이

concurrent_queue 클래스는 queue 클래스와 매우 유사합니다. 다음은 concurrent_queuequeue와 다른 점에 대한 설명입니다.

  • concurrent_queue 개체에 대한 큐에 대기시키기 및 큐에서 제거 작업은 동시성이 보장됩니다.

  • concurrent_queue 클래스는 동시성이 보장되지 않는 반복기 지원을 제공합니다.

  • concurrent_queue 클래스는 front 또는 pop 메서드를 제공하지 않습니다. concurrent_queue 클래스는 try_pop 메서드를 정의하여 이러한 메서드를 대체합니다.

  • concurrent_queue 클래스는 back 메서드를 제공하지 않습니다. 따라서 큐의 끝을 참조할 수 없습니다.

  • concurrent_queue 클래스는 size 메서드 대신 unsafe_size 메서드를 제공합니다. unsafe_size 메서드는 동시성이 보장되지 않습니다.

동시성 보장 작업

concurrent_queue 개체에서 큐에 대기시키거나 큐에서 제거하는 모든 메서드는 동시성이 보장됩니다.

다음 표에서는 동시성이 보장되는 일반적인 concurrent_queue 메서드와 연산자를 보여 줍니다.

empty

push

get_allocator

try_pop

empty 메서드는 동시성이 보장되지만 동시 작업을 수행하면 empty 메서드가 반환되기 전에 큐가 확장 또는 축소될 수 있습니다.

다음 표에서는 동시성이 보장되지 않는 일반적인 메서드와 연산자를 보여 줍니다.

clear

unsafe_end

unsafe_begin

unsafe_size

반복기 지원

concurrent_queue는 동시성이 보장되지 않는 반복기를 제공합니다. 디버깅 용도로만 이러한 반복기를 사용하는 것이 좋습니다.

concurrent_queue 반복기는 요소를 앞으로만 트래버스합니다. 다음 표에서는 각 반복기에서 지원하는 연산자를 보여 줍니다.

Operator

설명

operator++

큐에서 다음 항목으로 이동합니다. 이 연산자는 전위 증가 및 후위 증가 의미 체계를 둘 다 제공하도록 오버로드됩니다.

operator*

현재 항목에 대한 참조를 검색합니다.

operator->

현재 항목에 대한 포인터를 검색합니다.

[맨 위로 이동]

combinable 클래스

Concurrency::combinable 클래스는 세분화된 계산을 수행한 후 이러한 계산을 최종 결과로 병합하는 데 사용할 수 있는 재사용 가능한 스레드 로컬 저장소를 제공합니다. combinable 개체를 환산(reduction) 변수로 생각할 수 있습니다.

combinable 클래스는 여러 스레드 또는 작업 사이에서 리소스가 공유되는 경우에 유용합니다. combinable 클래스를 사용하면 잠금이 필요 없는 방식으로 공유 리소스에 액세스할 수 있으므로 공유 상태를 제거할 수 있습니다. 따라서 이 클래스는 여러 스레드에서 공유 데이터에 대한 액세스를 동기화할 때 뮤텍스와 같은 동기화 메커니즘 대신 사용할 수 있습니다.

메서드 및 기능

다음 표에서는 combinable 클래스의 중요한 메서드 중 일부를 보여 줍니다. 모든 combinable 클래스 메서드에 대한 자세한 내용은 combinable 클래스를 참조하십시오.

메서드

설명

local

현재 스레드 컨텍스트와 연결된 지역 변수에 대한 참조를 검색합니다.

clear

combinable 개체에서 모든 스레드 로컬 변수를 제거합니다.

combine

combine_each

제공된 combine 함수를 사용하여 모든 스레드 로컬 계산 집합에서 최종 값을 생성합니다.

combinable 클래스는 병합된 최종 결과에서 매개 변수화된 템플릿 클래스입니다. 기본 생성자를 호출하는 경우 _Ty 템플릿 매개 변수 형식에는 기본 생성자 및 복사 생성자가 있어야 합니다. _Ty 템플릿 매개 변수 형식에 기본 생성자가 없으면 초기화 함수를 매개 변수로 사용하는 오버로드된 버전의 생성자를 호출하십시오.

combine 또는 combine_each 메서드를 호출한 후 추가 데이터를 combinable 개체에 저장할 수 있습니다. combinecombine_each 메서드를 여러 번 호출할 수도 있습니다. combinable 개체의 로컬 값이 변경되지 않으면 combinecombine_each 메서드를 호출할 때마다 같은 결과가 나타납니다.

예제

combinable 클래스를 사용하는 방법에 대한 예제를 보려면 다음 항목을 참조하십시오.

[맨 위로 이동]

관련 항목

참조

concurrent_vector 클래스

concurrent_queue 클래스

combinable 클래스