하지만 스레드 라이브러리는 코어에 스레드 할당에 대해 걱정할 필요가 있습니다. 이것이 운영 체제의 일이 아닌가? Boost에 비해 TBB를 사용하는 실제 Benifit은 무엇입니까?
그렇습니다. 스레딩 라이브러리는 대개 스레드를 코어에 매핑하는 데 신경 쓰지 않아야합니다. 그리고 TBB는 그렇지 않습니다. TBB는 스레드가 아닌 작업으로 작동합니다. TBB의 스케줄러는 스레드 풀을 할당하고 실행할 작업을 동적으로 선택하도록하여 모든 코어를 활용합니다. 이는 Boost에 비해 주된 이점으로, 사용 가능한 작업을 스레드에 직접 매핑해야합니다. 그리고 나서 TBB는 가장 일반적인 병렬 패턴을 표현하고 작업으로 모든 조작을 숨기는 데 사용할 수있는 parallel_for, parallel_pipeline 등과 같은 상위 수준의 구조를 제공합니다. 예를 들어
,의는 만델 브로트 프랙탈의 포인트를 계산 코드의 조각을 보자 (http://warp.povusers.org/Mandelbrot/에서 가져온 변수 초기화가 생략) :
이제
for(unsigned y=0; y<ImageHeight; ++y)
{
double c_im = MaxIm - y*Im_factor;
for(unsigned x=0; x<ImageWidth; ++x)
{
double c_re = MinRe + x*Re_factor;
double Z_re = c_re, Z_im = c_im;
bool isInside = true;
for(unsigned n=0; n<MaxIterations; ++n)
{
double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
if(Z_re2 + Z_im2 > 4)
{
isInside = false;
break;
}
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
}
if(isInside) { putpixel(x, y); }
}
}
그것이 TBB과 평행하게, 당신이 필요로 변환하는 것입니다 TBB에 가장 바깥 쪽 루프 :: parallel_for (나는 간결을위한 C++ 11 람다 사용) :
tbb::parallel_for(0, ImageHeight, [=](unsigned y)
{
// the rest of code is exactly the same
double c_im = MaxIm - y*Im_factor;
for(unsigned x=0; x<ImageWidth; ++x)
{
...
// if putpixel() is not thread safe, a lock might be needed
if(isInside) { putpixel(x, y); }
}
});
TBB가 자동으로 사용할 코어를 통해 모든 루프 반복을 배포합니다 (얼마나 많은 당신이 귀찮게하지 않습니다) 및 동적 부하와 균형을 맞춘다. 일부 스레드가 더 많은 작업을해야한다면, 다른 스레드는 기다리지 않고 도움을 받아 CPU 사용을 극대화합니다. 원시 스레드로 구현해보십시오. 차이점을 느낄 것입니다.
pthread를 사용하여 스레드 유사성을 설정할 수 있습니다 (예 : pthread_setaffinity_np 호출 사용). –
@Foo 예가 옳습니다. 내 요점은 실용적인 사용이 그 일을 얼마나 많이하는지입니다. 프로그래머는 응용 프로그램에서 수행되는 스레드 예약 작업을 원하지 않을 수 있습니다. 그렇다면 왜 TBB가 이것을 다른 도서관과의 차별화라고 표현합니까? – David
애플리케이션을 위해 코어를 적절히 선택하는 것이 관찰 가능한 이점입니다. 스레드 로거의 간단한 예제를 살펴보십시오. 하나의 스레드는 네트워크 인터페이스로부터 데이터를 수신하여 링 상에 놓습니다. 다른 스레드는 링에서 읽고 파일에 씁니다 (tcpdump를 사용하면 혼잡을 덜어줍니다). 이 경우 듀얼 프로세서 시스템에서 동일한 CPU에 대한 유사성 설정이보다 효율적입니다.하이퍼 스레딩이 활성화 된 경우 가상 코어 쌍을 사용하는 것이 훨씬 빠릅니다. 그러나 이것은 TBB가 필요로하지 않는 많은 마이크로 관리를 필요로합니다. –