MSDN에 있는 글을 옮겨와 봤습니다^^

 

다른 프로세서에서 사용되고 있는 복수의 동시실행 태스크가 같은 캐시라인에 배치되어 있는 변수에 쓰기를 하면 거짓 공유가 발생한다. 하나의 태스크가 어떤 변수에 쓰기를 하면 양쪽 변수의 캐시라인이 무효화된다. 캐시라인이 무효화 될 때마다 재 로딩이 필요하게 된다. 즉 거짓 공유가 발생하면 애플리케이션의 성능이 저하할 위험이 크다.

 

long count1 = 0L;

long count2 = 0L;

concurrency::parallel_invoke(

   [&count1] {

      for(int i = 0; i < 100000000; ++i)

         ++count1;

   },

   [&count2] {

      for(int i = 0; i < 100000000; ++i)

         ++count2;

   }

);

long count = count1 + count2;

위의 코드는 태스크에 공유 변수를 사용하지 않기 위해 count1, count2로 변수를 나누어서 사용하고 있다. 그래서 일견 보기에는 서로 독립적으로 실행될 것이라고 생각할 수 있다. 그러나 위에 설명했듯이 count1 count2는 서로 같은 캐시라인에 배치될 확률이 높아서 결과적으로 거짓 공유가 발생한다.

 

이 문제를 해결하기 위해서는 아래처럼 메모리 정렬에 의해 서로 다른 캐시라인에 배치되도록 한다.

__declspec(align(64)) long count1 = 0L;     

__declspec(align(64)) long count2 = 0L;     

concurrency::parallel_invoke(

   [&count1] {

      for(int i = 0; i < 100000000; ++i)

         ++count1;

   },

   [&count2] {

      for(int i = 0; i < 100000000; ++i)

         ++count2;

   }

);

long count = count1 + count2;

핵심은 __declspec(align(64))으로 메모리 캐시 사이즈가 64바이트 이하인 경우 같은 캐시라인을 사용하지 않도록 해준다.

 

 

__declspec 설명

http://blog.naver.com/riverrun27/40126498899

 

 

by 흥배 2014. 2. 3. 08:00
  • 크로스 2014.02.03 10:30 ADDR EDIT/DEL REPLY

    msdn에 있는 내용이면 VS계열의 컴파일러에서만 동작하는 키워드인가요?
    gcc등으로 컴파일해서 리눅스계열의 운영체제에서 돌아갈 수 있는 프로그램은 못만드나 싶어서 여쭤봅니다 ^^;;
    만약 어떤 프로그램을 리눅스로 개발해야 한다면 위 키워드는 사용할수 없는지요?

    • 흥배 2014.02.03 15:43 신고 EDIT/DEL

      구글링 해보니 gcc에서는 __attribute__ 라는 키워드를 사용한 것 같습니다. http://stackoverflow.com/questions/7281699/aligning-to-cache-line-and-knowing-the-cache-line-size

  • ruwin126 2014.05.01 22:15 ADDR EDIT/DEL REPLY

    캐시 라인이 64 byte 이하여야 하고(이건 지금 나오는 대부분의 머신이 만족하겠지만) 120바이트의 낭비되는 공간이 있다는 것에서 딱히 추천할 만한 방법은 아닌 것 같네요.
    combinable을 이용하는건 어떻게 생각하세요?

VC10에서 병렬 프로그래밍 라이브러리인 Concurrency Runtime 이라는 것이 추가되었습니다.

Concurrency RuntimeOS의 스레드 관리 보다 좀 더 지능적으로 관리를 하며, Concurrency Runtime Windows 7에서 새로 추가된 UMS(User Mode Scheduler)를 사용하고 있습니다.

 

Windows7 이상의 OS에서 64비트 프로그래밍을 한다면 UMS를 사용하는 것이 좋습니다. 그런데 UMS를 사용하는 방법에 대해서 잘 나온 것이 없습니다. 그래서 UMS를 알아도 활용할 방법이 애매한데 이 문제를 해결하는 방법은 Concurrency Runtime의 스케쥴러에서 스레드를 만드는 것입니다. 기존의 스레드를 만드는 방법과 거의 비슷해서 손 쉽게 이전 코드에서 수정도 가능합니다.

 

 

사용하는 방법은 MSDN의 예제를 참고하면 됩니다.

http://msdn.microsoft.com/en-us/library/vstudio/ee624185.aspx

 

제가 간단하게 설명하자면....

아래의 헤더 파일을 포함합니다

#include <concrt.h>

 

네임스페이스를 선언합니다.

using namespace Concurrency;

 

스레드에서 호출할 함수를 정의합니다.

void __cdecl MyThreadFunction(LPVOID param);

 

스레드에 넘겨줄 데이터를 정의합니다.

typedef struct MyData {

    int val1;

    int val2;

    event signal;

} MYDATA, *PMYDATA;

 

 

Concurrency Runtime의 스케쥴러에서 스레드를 생성합니다.

CurrentScheduler::ScheduleTask(MyThreadFunction, pData);

 

 

위의 MyData 구조체에서 event signal 이 사용되는 경우는 만약 메인 스레드에서 생성한 워커 스레드가 종료 될 때까지 대기하고 싶을 때 사용하면 좋습니다.

메인 스레드에서 아래와 같이 하면 워커 스레드가 종료될 때까지 대기 합니다.

pData->signal.wait();

 

워커 스레드는 스레드가 종료될 때 아래와 같이 해서 이벤트를 발생하여 메인 스레드의 대기를 풀어줍니다.

pData->signal.set();

 

 

by 흥배 2013. 3. 4. 08:00

C#이나 Java와 다르게 C++(물론 C)은 동적 메모리 할당과 해제에 신경을 써야 합니다. 그리고 높은 성능까지 원한다면 메모리 관리자를 직접 만들어서 동적 할당과 해제를 직접 관리하여 실시간으로 동적 할당이 일어나지 않도록 해야 합니다.

 

그러나 범용적인 목적을 가지 메모리 관리자는 만들기가 쉽지 않고 특히 멀티 스레드 환경에서 사용해야 하는 경우는 잘못하면 오히려 더 느려질 수 있습니다.

 

현재 Windows에서는 LFH를 사용하여 이전보다 동적 할당과 해제에 대한 성능을 개선했습니다. 그러나 이것보다 더 성능을 좋게 하는 방법이 있습니다.

그것은 VC++10에서 추가된 라이브러리인 Concurrency Runtime에서 제공하는 메모리 관리자를 사용하는 것입니다.

메모리 할당을 할 때는 Concurrency::Alloc, 메모리 해제를 할 때는 Concurrency::Free 를 사용합니다.

 

MSDN에 있는 샘플 중 new/delete, malloc/free와 비교한 것을 보면 new/delete에 비해서는 3배 정도 성능이 좋습니다.

http://msdn.microsoft.com/en-us/library/dd998050.aspx

 

 

by 흥배 2013. 1. 29. 22:03
  • Lyn 2013.01.30 11:55 ADDR EDIT/DEL REPLY

    누가 할당자로 만들어줬으면 좋겠네요 ㅎㅎ

    • 흥배 2013.01.30 20:29 신고 EDIT/DEL

      크게 힘들지 않을 것 같은데 다른 사람들이 안만들고 있으면 다음에 시간 나는대로 만들어서 공유하겠습니다^^

  • 용태군 2013.02.13 18:19 ADDR EDIT/DEL REPLY

    병렬프로그래밍 코드가 쓰일때만 성능향상이 있는거같은데 맞나요?
    쓰레드가 여러개 있다 하더라도. new/delete가 겹치는 부분이 적으면 성능에 저하가 발생하는거 같은데요.

  • nolimitk 2016.01.06 14:49 ADDR EDIT/DEL REPLY

    테스트 코드도 테스트 결과도 잘못되었습니다.
    ptmalloc의 t-test1정도는 되야 제대로 된 테스트라고 볼수 있는데요.
    각각의 allocation을 테스트하기 위해서는 process를 별도로 실행해야 하며
    한번만 실행한 결과를 내놓는 테스트는 신뢰성이 떨어집니다.
    (process가 처음 실행한 다음 처음 할당을 받을때는 backend heap에서 block을 가져와야 하므로 무조건 제일 느립니다.)

    제가 실제로 테스트 해 본결과 LFH( malloc )와 별 차이 없었습니다.

TBB
TBB의 스케줄러는 협조적 멀티태스크를 행하기 때문에 태스크 안에서 장기간 블럭되는 처리를 호출하면 안된다.
다른 태스크를 스케줄 할 수가 없게되고, CPU 리소스의 재 이용률이 악화한다


PPL
PPL/ConcRT에서는 유저모드 스케줄러(UMS) 스레드를 이용하므로 태스크 안에서 블럭킹 API를 호출하여도 CPU 이용률이 저하되지 않는다.
ConcRT에서는 협조 블럭킹 기능을 제공하기 때문에 블럭 중 다른 태스크가 스케줄링 된다.
단 UMS는 Windows Server 2008 R2 또는 Windows 7(64비트) 이후의 64비트판에서만 지원한다.
그 이외의 Windows OS 상에서는 일반적인 스레드로 이용된다.





출처 : MSDN
by 흥배 2012. 3. 7. 09:00

VS2010 팀 블로그에서 강좌 연재 중인 Concurrency Runtime AAL의 강좌가 끝났습니다.

강좌를 연재한 분은 멈비님으로 짧은 시간에 열심히 활동하셨습니다. 그리고 이후에도 계속 Concurrency Runtime에 대한 강좌 글을 올려 주실 예정입니다.

 

병렬 프로그래밍에 관심 있는 분들은 아래의 글을 읽어보시기 바랍니다.

 

Asynchronous Agents Library 소개

Asynchronous Agents Library - agent. 1 ( 상태 )

Asynchronous Agents Library – agent. 2 ( 기능 )

Asynchronous Agents Library - message 전달 함수. 1 ( 전송 )

Asynchronous Agents Library – message 전달 함수. 2 ( 수신 )

Asynchronous Agents Library – message block 1. ( 인터페이스 )

Asynchronous Agents Library – message block 2. ( unbounded_buffer )

Asynchronous Agents Library – message block 3. ( overwrite_buffer & single_assignment )

Asynchronous Agents Library – message block 4. ( call )

Asynchronous Agents Library – message block 5. ( transformer )

Asynchronous Agents Library – message block 6. ( choice )

Asynchronous Agents Library – message block 7. ( join & multitype_join )

Asynchronous Agents Library – message block 8. ( timer )



by 흥배 2010. 8. 16. 09:00

VSTS 2010 VC++ 10의 큰 핵심 feature 두 가지를 뽑으라고 하면 저는 C++0x와 Concurrency Runtime 두 가지를 뽑고 싶습니다.

VC++ 10
은 시대의 변화에 맞추어 새로운 C++ 표준과 병렬 프로그래밍을 받아들였습니다.

현재도 Win32 API에 있는 Thread  관련 API를 사용하여 병렬 프로그래밍을 할수 있습니다. 하지만 이것만으로 병렬 프로그래밍을 하기에는 너무 불편합니다.
그래서 VC++ 10에는 Concurrency Runtime 이라는 것이 생겼습니다.



Concurrency
Parallel의 차이


........................


나머지는 여기에서 봐 주세요^^

by 흥배 2009. 7. 30. 18:02
| 1 |