2012-03-28 2 views
1

다음과 같이 스레드 로컬이 아닌 배열이 있습니다.비 스레드 로컬 데이터를 가리키는 스레드 로컬 포인터

long array[NTHREADS]; 

여기서 array [0]은 스레드 0으로, array [1]은 스레드 1로 관리하는 식으로 배열됩니다. 어떤 지점에서는 쓰레드가 다른 쓰레드의 부분을 읽어야하기 때문에 쓰레드 로컬 변수를 사용하지 않았습니다. 그러나 대부분의 경우 자신의 부분을 수정합니다. 물론 우리는 array[thread_id]을 사용하여 데이터를 수정할 수 있지만 실행 속도를 높이기 위해 포인터를 사용하고 싶습니다.

이제 각 스레드가 자체 데이터를 관리하므로 포인터는 로컬 스레드이며 처음에 할당되어야합니다. 그래서 나는 이와 같은 것을 필요로한다 (gcc 구문으로). 이런 식으로

__thread long* tl_ptr; 

    tl_ptr = &array[threadid]; 

, 나는 *tl_ptr를 사용하여 스레드가 특정 데이터를 수정할 수 있습니다. 이제이 질문이 올바른 방법일까요? 이 접근법에 문제가 있습니까?

+0

_we, 난 pointer._ ← 조기 최적화 저쩌구 ... _Here 어레이 [0] 스레드 0에 의해 관리되는, 배열 [1 사용할 ] 스레드 1 등으로 on._ 당신은 더 나은, 더 나은 아직 사용을 캐시 줄 경계에 각 요소를 정렬하거나, 여러 개의 CPU에서 배열을 수정할 경우, CPU에서 CPU에 수신 거부 캐시 라인을해야 ← @ drhirsch의 접근 방식. – ninjalj

답변

1

C++ 11에는 이러한 상황에서 동작을 정의하는 메모리 모델이 있습니다. C 및 C++ 03 이전 버전은 기본적으로 단일 스레드입니다 (기본 원자/펜스 없음).

이것은 메모리 모델을 구현하는 C++ 11 컴파일러를 사용하지 않으면 캐시 일관성 문제 등으로 인해 이상한 결과가 발생할 수 있음을 의미합니다. 이것은 CPU 관련 사항입니다.

실행중인 프로세서가 무엇인지 알면 적절하게 "강력한"메모리 모델이 있으므로 접근 방법이 안전하다고 입증 할 수 있지만 이식 할 수는 없습니다.

+0

제 질문은 원자 변수에 관한 것이 아닙니다. 스레드가 아닌 로컬 배열을 가리키는 스레드 로컬 포인터를 사용하는 것이 좋은지 묻는 것입니다. – pythonic

+0

예 * 메모리 모델이 강하면 *. 포인터의 값은 포인터가 스레드 로컬인지 여부에 관계없이 같습니다. 중요한 것은 메모리 모델입니다. – spraff

0

이전 C++ 11 언어로 프로그램을 작성하는 경우 엄격한 결과는 이식 가능하지 않습니다. 이전 C++ 방언에는 스레드 개념이 없습니다.

그러나 C++ 11을 사용하는 경우 (이는 단일 바이트 및 컴파일러 플래그의 사용을 변경하지 않고 "This is now C++ 11"이라고 말할 수 있음) 언어의 스레딩 기능을 고수하십시오 (__thread 대신 thread_local), 이식성은 언어에 의해 보장됩니다.

프리 C++ 11의 대부분의 구현은 스레드와 합리적으로 잘 작동합니다. gccx86_64 등이 작동합니다 - gcc는 스레딩 메커니즘을 내장하고 있으며 x86_64는 강력한 메모리 모델을 사용하는 아키텍처입니다 (메모리 주문 장에서 here에 대한 정보 참조).

즉, 당신은 이상한 방법으로 로컬 스레드를 사용했다. 일반적인 의미는 당신이 어떤 스레드에서 array_data을 수정하는 경우, array_data의 스레드 로컬 복사본을 수정 얻을 것이다

__thread long array_data; 
long* array[NTHREADS]; // non thread local pointer to thread local data 

지금이다. 다른 스레드에서 array_data에 액세스해야하는 경우, 모든 array_data을 요약 감독자 스레드 말, 당신은 요소

array[iThread] = &array_data; // where iThread is an index for each thread 
각 스레드의 시작을 초기화하는 모든 스레드 지역 주민과 포인터를 보유하고 배열이 필요합니다 당신은 직렬화 또는 해당되는 경우 뮤텍스로 보호되어 다른 스레드에서 지역 주민을 스레드에 반드시 액세스 할 필요가
long sum=0; 
for (int i=0; i<NTHREADS; ++i) 
    sum += *array[i]; 

같은 관리자 스레드에서

액세스 보일 것이다.귀하의 경우 (x86 및 gcc) 합계 루프는 작동합니다 - 정렬 된 long은 하드웨어에 의해 원자 적으로 보장되며 gcc는 포인터를 제한되지 않은 것으로 보지만 조심하십시오. 어레이 [thread_id]을 사용하여 데이터를 수정할 수 있지만, 실행 속도를 높이는

관련 문제