2017-02-08 20 views
3

펜스를 사용하여 C11에서 비 원자 연산의 동작을 판단 할 수있는 방법이 있습니까? 특히, 특정 필드가 int 일 필요가있는 상황에서 코드를 읽거나 쓰거나 시스템 호출 인수로 전달할 수있는 이전 인터페이스와의 호환성을 위해 코드를 안전하게 만들고 싶습니다. atomic_intint과 같은 크기 일 필요는 없으므로 atomic_int을 사용할 수 없습니다.C11에서 원자가가 아닌 울타리

#include <stdatomic.h> 
#include <stdio.h> 
#include <threads.h> 

int ready; /* purposely NOT _Atomic */ 
int value; 

void 
p1() 
{ 
    value = 1; 
    atomic_thread_fence(memory_order_release); 
    ready = 1; 
} 

void 
p2(void *_ignored) 
{ 
    while (!ready) 
    ; 
    atomic_thread_fence(memory_order_acquire); 
    printf("%d\n", value); 
} 

int 
main() 
{ 
    thrd_t t; 
    thrd_create(&t, p2, NULL); 
    p1(); 
    thrd_join(&t, NULL); 
} 

내 특정 질문은 위의 코드를 수정하는 것이 가능 여부 :

여기에 불행히도 때문에 ready의 데이터 인종, 섹션 5.1.2.4 문단 25에 따라 정의되지 않은 동작을 생산하는 최소한의 작업 예제 ready_Atomic으로 변경하지 않고 인쇄 1을 보장합니다. (readyvolatile으로 만들 수 있지만이 방법이 도움이된다는 제안이 표시되지 않습니다.)

관련 코드는 위의 코드를 작성하는 것이 안전한지 여부입니다. 캐시 일관성이 있습니까? C11 프로그램에 소위 양성 종족이 포함되어있을 때 manythings으로 이동한다는 것을 알고 있습니다. 따라서 데이터 레이스와 정의되지 않은 일반적인 경고가 아닌 위의 코드에서 가능한 컴파일러와 아키텍처의 세부 사항을 찾고 있습니다. 행동.

+0

C11의 모든 동기화 작업은 원자 단위 (또는 'mtx_t')에서만 작동합니다. 원자가 없으면 결코 작동하지 않습니다. 일단 당신이 상태를 제어하는 ​​원자를 가지면, 비 원자력 (non-atomci) 객체들에 대한 효과에 대해서조차도, 쓰레드에서 보이는 효과가 나타나기 전에 일어나는 관계로 논쟁 할 수있다. **하지만 ** 당신의 것들을 오래된 인터페이스와 "호환"하게 만드는 것은 C11의 원자 단위로는 절망적입니다. 그들은 이것을 위해 만들어지지 않았습니다. 시스템의 상태에 따라 이러한 오래된 인터페이스가 비 원자 적으로 작동하도록하여 사용자가 생각할 수있는 일관성의 증거로 구멍을 뚫습니다. –

+0

@JensGustedt 그러나, 제 질문은 울타리에 관한 것이지, 분광에 관한 것이 아닙니다. 울타리는 비 원자 메모리 연산의 순서를 제한합니다. 이 특정 예에서, 릴리스 펜스는 획득 펜스보다 먼저 발생하기 때문에 '준비'상태에서만'value'에 경쟁이 없습니다. 그래서 아마도 두 가지 경우 모두에서'memory_order_acq_rel'을 사용하겠습니까? – user3188445

+0

아니,이 문제에 대해 당신이 잘못 생각한 것 같습니다. 다른 스레드의 두 울타리는 원자 단위로만 동기화됩니다. 한 울타리가 다른 것에 의해 감지되는 원자 물체를 수정하지 않고 다른 울타리보다 앞서 일어난다 고 주장 할 수있는 다른 방법은 없다. –

답변

1

울타리를 사용하여 C11에서 비 원자 연산의 동작을 판단 할 수있는 방법이 있습니까?

당신이 울타리를 사용하는 방법은 정확하지만, 프로그램의 동작에 대해 추론 할 수 있도록하려면 이 가게 사이에 엄격한 스레드 간 수정 명령이 있는지 확인하는 것은 귀하의 책임입니다 (1) ~ ready 및 그로부터의 하중 (1). 일반적으로 atomic 변수가 적용됩니다. C11 표준에 따라 ready에 데이터 경쟁이 있고 (예상대로) 정의되지 않은 동작이 예상 할 수있는 것입니다.

필자가 궁금해하는 질문은 준비를 _Atomic으로 변경하지 않고 인쇄 1을 보장하기 위해 위 코드를 수정할 수 있는지 여부입니다. (나는 휘발성 준비 할 수 있지만 도움이 될 것을 사양에서 어떤 제안이 표시되지 않습니다.)

기준은 답을 준수하는 것은 없다 '더'표준이 사건을 지원하지 않기 때문에 당신이 원 이 문맥에서 volatile와 관련된 것을 찾지 못했습니다.

그러나 표준 중 하나는 많은 아키텍처와의 호환성을 지원한다는 점을 고려하여 표준이 엄격하게 적용됩니다. 그렇다고해서 데이터 경쟁이 항상 각 플랫폼에서 문제가되는 것은 아닙니다.

공유 컨텍스트에서 비 원자형을 사용할 때의 문제는 까다 롭습니다. 사람들은 때로 int과 같은 유형의 CPU 작업을 분할 할 수 없다면 atomic_int의 대체품으로 사용할 수 있다고 생각하는 경우가 있습니다.'원자'넓은 파급 효과와 개념이기 때문에 이것은 사실이 아니다 :

  • 불가분의 읽기/쓰기 -이 많은 플랫폼에서 일정한 유형에 적용됩니다.

  • 제한된 최적화 - 컴파일러 변환은 많은 예상치 못한 방식으로 실제로 정의되지 않은 동작을 유발할 수 있습니다. 컴파일러는 메모리 연산을 재정렬하고 동일한 메모리 위치에있는 다른 변수와 변수를 결합 할 수 있습니다. 루프에서 변수를 제거하고 레지스터에 유지하는 등의 작업을 수행 할 수 있습니다. 변수를 선언하면 많은 것을 방지 할 수 있습니다 volatile 컴파일러가 wrt 최적화를 수행 할 수있는 것에 제약이 있습니다.

  • 코어 사이의 데이터 동기화 - 귀하의 경우에는 저장소와로드간에 ready에 스레드 간 순서가 엄격한 조건에서 펜스가 처리합니다. 실제 atomic_int 인 경우 편안한 작업을 할 수있었습니다. 코드가 작동하는지

는 플랫폼과 컴파일러에 따라 다르지만 적어도 ready 플래그 volatile을 선언합니다. gcc -O3 컴파일러 최적화를 사용하여 X86_64에서 테스트를 수행했지만 volatile없이 끝없는 루프에 걸렸습니다.
원자 및 비 원자의 경우 컴파일러에서 생성 한 지침의 차이점을 비교하는 것도 좋은 생각입니다.

위의 코드를 작성하는 것이 안전한지 여부는 내 코드에서 실행될 컴퓨터가 캐시 일관성을 갖고 있기 때문입니까?

캐시 일관성을 지원하지 않는 시스템은 분명히 프로그램하기가 어렵 기 때문에 분명히 캐시 일관성이 필요합니다. 캐시 일관성 없이는 거의 확실히 작동하지 않을 것입니다.