프로세서가 POSIX 공유 메모리에 대한 변경 사항을 인식하지 못합니까?

프로세서가 POSIX 공유 메모리에 대한 변경 사항을 인식하지 못합니까?

문맥:나는 사용하고있다POSIX 공유 메모리프로세스 그룹을 위한 공유 메모리 공간을 제공합니다. 나는 데이터를 공유하기 위해 한동안 이 방식을 사용해 왔고 잘 작동합니다. 그런데 최근 특정 유형의 프로그램에서 이상한 문제가 발생했습니다.

질문:나는 각 프로세스가 공유 메모리 공간의 공유 합계에 값을 기여해야 하는 프로그램을 작성했습니다. 이전에 공유 객체가 메모리에 매핑되었을 때 합계는 0으로 초기화되었습니다. 그러나 각 프로세스가 공유 합계에 자신의 일부를 추가하려고 하면최신 값을 볼 수 있지만 덧셈의 결과는 항상 자신의 값에 0을 더한 것과 같습니다.. 아래를 참조하세요:

[21017] Adding 6 to 0!
[21020] Adding 33 to 0!
[21016] Adding 15 to 0!
[21018] Adding 24 to 0!
[21017] Got access! (0x7fe953fcb000 = 0)
[21017] Done (0x7fe953fcb000 = 6)
[21016] Got access! (0x7fe953fcb000 = 6)
[21016] Done (0x7fe953fcb000 = 15)
[21018] Got access! (0x7fe953fcb000 = 15)
[21018] Done (0x7fe953fcb000 = 24)
[21020] Got access! (0x7fe953fcb000 = 24)
[21020] Done (0x7fe953fcb000 = 33)
Sum = 33

각 프로세스는 작성된 최신 값을 "보지만" 자체 구성 요소를 추가한 후에는 기존 값을 무시하는 것 같습니다. 공유 메모리 공간에 누가 쓸 수 있는지 관리하는 접근 제어 시스템이 있기 때문에 각 접근이 순차적으로 정렬되는 것을 볼 수 있습니다. 사용된 테스트 프로그램은 다음과 같습니다(독자가 실행하는 것을 원하지는 않지만).

int main (void) {
    int local_sum = 0, gid = -1;
    volatile int *sum;

    // Fork for four processes.
    for (int i = 1; i < 4; i++) {
        if (fork() == 0) break;
    }

    // Initialize the DSM. Set GID.
    sum = (int *)dsm_init(&cfg);
    gid = dsm_get_gid();

    // Compute range.
    for (int i = 0; i < 3; i++) {
        local_sum += array[(gid * 3) + i];
    }

    // Add to local sum.
    printf("[%d] Adding %d to %d!\n", getpid(), local_sum, *sum);
    *sum = *sum + local_sum;

    // Barrier.
    dsm_barrier();

    // Print sum if process zero.
    if (gid == 0) printf("Sum = %d\n", *sum);

    // Exit.
    dsm_exit();
}

각 프로세스가 공유 공간의 주소에서 올바른 값을 "볼" 수 있지만 0x7fe953fcb000추가 후에는 추가하는 동안 해당 주소의 값이 여전히 0인 것처럼 동작하는 이유는 무엇입니까?


이 문제에 대해 나를 괴롭히는 점은 다음과 같습니다.

  • 캐시 문제인 경우 산술 연산 전에 올바른 값을 인쇄할 수 있는데 여전히 올바르지 않은 이유는 무엇입니까?
  • 프로세스 힙에 공유 값을 추가하고 있습니다. 컴파일러는 값이 0이라고 가정하고 아무것도 최적화할 수 없습니다.

왜 이런 일이 발생하는지에 대한 설명이 있습니까? 나는 무슨 일이 일어났는지 알아보기 위해 내 프로그램에서 GDB를 사용해 보았습니다. 그러나 내가 아는 한 그것은 단지 메모리 주소의 값을 레지스터로 이동시키는 것뿐입니다. 최적화 문제는 본 적이 없습니다.

답변1

내가 볼 수 있는 바로는 4개의 프로세스가 빠르게 연속적으로 생성되어 각각 *sum += some_value 작업을 수행하려고 합니다. 더하기 전에 둘 다 *sum이 0이라고 생각하는 것은 전적으로 가능합니다.

추상 어셈블리 구문을 사용해 보겠습니다. C 문

*sum = *sum + local_sum

으로 컴파일됩니다

LOAD *sum into R0
LOAD local_sum into R1
ADD R1 to R0
STORE R0 to *sum

4개의 프로세스가 시퀀스를 실행하기 위해 경쟁합니다. 둘 중 하나가 R0을 *sum에 저장하기 전에 둘 다 LOAD *sum을 *sum에 저장하는 것이 전적으로 가능합니다. 실제로 STORE R0에 의해 트리거된 시스템 호출이 있다는 점을 고려하면(재계획 지점도 마찬가지입니다) *음, 좋은 기회네요. 예를 들어 세마포어를 사용하여 공유 변수에 대한 액세스를 동기화해야 합니다.

관련 정보