스레드 간 거짓 공유는 2 개 이상의 스레드가 동일한 캐시 라인을 사용하는 경우입니다.
예. :
struct Work {
Work(int& d) : data(d) {}
void operator()() {
++data;
}
int& data;
};
int main() {
int false_sharing[10] = { 0 };
boost::thread_group threads;
for (int i = 0; i < 10; ++i)
threads.create_thread(Work(false_sharing[i]));
threads.join_all();
int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 };
for (int i = 0; i < 10; ++i)
threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS]));
threads.join_all();
}
첫 번째 블록의 스레드는 거짓 공유로 고통받습니다. 두 번째 블록의 스레드는 없습니다 (덕분에 CACHELINE_SIZE
).
스택의 데이터는 다른 스레드와 항상 멀리 떨어져 있습니다. (예 : 창 아래, 최소 두 페이지 이상).
함수 개체의 정의에서 Work
의 인스턴스가 힙에 만들어지고이 힙 공간이 스레드 내부에서 사용되므로 false 공유가 나타날 수 있습니다.
이렇게하면 여러 개의 Work
인스턴스가 인접 해져 캐시 라인을 공유 할 수 있습니다.
하지만 데이터가 외부로 절대 전달되지 않아 잘못된 공유가 불필요하게 유도되므로 샘플이 이해가되지 않습니다.
가장 쉬운 방법은 이와 같은 문제를 방지하기 위해 '공유'데이터를 스택에 로컬로 복사 한 다음 스택 복사본에서 작업하는 것입니다. 작업이 끝나면 출력 var로 다시 복사하십시오.
예컨대 :
struct Work {
Work(int& d) : data(d) {}
void operator()()
{
int tmp = data;
for(int i = 0; i < lengthy_op; ++i)
++tmp;
data = tmp;
}
int& data;
};
이 공유로 모든 문제를 방지 할 수 있습니다.
코드가 더 잘 작동합니다. 함수 객체가'정적'데이터를 가지고 있다면, 모든 쓰레드는 그 데이터를 공유 할 것입니다. – GManNickG
"각 스레드는 자신의 사본을 얻습니다"및 "정적으로 할당 됨"이 무엇을 의미하는지 정확하게 말해야한다고 생각하십시오. 스레드가 서로의 사본을 사용합니까? – Elemental
@ Elemental : 일부 컴파일러는 TLS- 스레드 로컬 저장소를 사용할 수 있습니다. 이는 느리지 만 정적으로 스레드를 안전하게 할당 할 수 있음을 의미합니다. – Puppy