다중 스레드 프로그램에서 일부 전역 구조를 사용합니다. 일부 구성원은 동시에 여러 스레드로 수정되고 다른 일부는 수정되지 않습니다.GCC 내장형 원자재 및 휘발성 코드
나는이 멤버를 volatile로 정의하지 않았지만 언제든지이 멤버를 읽기 및 쓰기 목적으로 사용할 때마다 __sync_fetch_and_add와 같은 기본 내장 명령을 사용합니다.
질문은이 멤버 또는 전체 struct volatile을 정의해야합니까?
나는이 builtins (lock 접두사) 때문에 컴파일러가 메모리에 액세스해야한다고 생각한다. 경쟁 조건이 아닌 다른 멤버에 대해 걱정해야한다.
나는 내 컴파일러 (gcc 4.6.2)의 어셈블리 출력을 체크 아웃하고 내 가정이 맞은 것 같습니다.
다음은 테스트 코드입니다.
int sum = 0;
for (i=0; i<2000000000; i++) {
sum += i;
}
어셈블리 출력 (-O2 -S -masm = 인텔)
L2:
add edx, eax
inc eax
cmp eax, 2000000000
jne L2
따라서 컴파일러 (EAX = 1, EDX = 총합) 여기서
이되는 메모리를 액세스하지 않는다 두 번째 테스트 코드. 예상대로
volatile int sum = 0;
for (i=0; i<2000000000; i++) {
sum += i;
}
어셈블리 출력
L2:
mov edx, DWORD PTR [esp+28]
add edx, eax
mov DWORD PTR [esp+28], edx
inc eax
cmp eax, 2000000000
jne L2
컴파일러마다 합계 메모리 액세스.
최종 코드, 내 방식.
int sum = 0;
for (i=0; i<2000000000; i++) {
__sync_fetch_and_add(&sum , i);
}
조립품 출력.
L2:
lock add DWORD PTR [esp+28], eax
inc eax
cmp eax, 2000000000
jne L2
이전의 edx와 같은 임시 레지스터조차도 컴파일러는 매번 메모리에 액세스했습니다.
그래서 volatile 멤버를 여러 스레드로 수정하거나 한 번에 하나의 스레드로만 수정하면 volatile을 정의하지 않습니다. 나는 안전합니까?
미리 감사드립니다.
휘발성은 대부분의 경우 피하는 것이 가장 좋습니다. 멀티 스레딩과 관련이 없습니다. 명시 적 장벽을 대신 사용하십시오. –
나는 그렇게 생각한다.thread1에서 루프에서 전역 변수를 사용하고 컴파일러가 메모리 액세스 대신 레지스터를 사용하면 thread2가 메모리에서이 변수를 수정할 수 있고 결과가 엉망입니다. – Kurt
절대적으로 그렇지 않습니다! [이 답변보기] (http://stackoverflow.com/questions/6866206/volatile-and-createthread/6866927#6866927)를 참조하십시오. GCC의 _sync 함수는 장벽으로 작동합니다. –