2016-08-16 8 views
-2

목적 :리눅스 공유 메모리/SMP

나는 세 가지 프로세스를 동기화 할, 그래서 프로세스 사이에 공유 메모리를 사용하여 생각했다. 그래서 저는 하나의 프로세스에서 두 개의 자식을 포크하고 자식을 생성하기 전에 공유 메모리 세그먼트를 생성했습니다. 저의 의도는 다른 코어에서 자식 프로세스와 부모 프로세스를 실행하여 병렬 실행되도록하는 것입니다. 그래서 친화력 컨트롤을 사용하여 해당 CPU를 할당했습니다. 두 자식은 공유 메모리를 통해 부모로부터 트리거를 얻을 때까지 루프 (할당 된 동일한 CPU에서 소비) 동안 무기한 대기합니다. 따라서 부모가 특정 문자/문자열을 쓸 때, 자식은 루프 밖으로 나와 나머지 코드를 실행해야합니다.

문제 :

공유 메모리 즉 변수 "SHM"에 변화가 자식 프로세스를 볼 수 없습니다 결코 while 루프에서 온다.

일부 심판 :

나는 문제는 무효화 특정 코어 프로세스를 이동 한 후 더러운 이루어지지하는 L2 캐시의 느낌. 따라서 코어는 여전히 공유 메모리의 이전 값을 참조합니다. 이는 최적화 수준이 O2보다 "0"이상인 경우에만 발생합니다. O0으로 강제하면 문제가 보이지 않습니다. 캐시를위한 Linux 커널 및 프로세서 자체의 배경에 대해서는 잘 모르겠습니다. 그래서 나는 일시적으로 코드를 수정하여이 문제를 없애기 위해 항상 "휘발성"을 사용하는 RAM에서 변수를 참조합니다.

예 :

현실에서이 문제를 보려면, 내가 "목적"에서 설명한 것과 동일한을 수행하는 샘플 코드를 부착했다.

내 질문 :

  • 이 예상 된 결과인가?
  • 그래서 Linux는 다른 CPU 코어에서 을 실행하는 프로세스간에 메모리를 공유하지 않습니다.

적어도 AFAIK 커널은 항상 동일한 코어에서 동일한 종류의 프로세스를 예약하므로 프로세스가 다른 코어로 이동하지 않으면이 시나리오를 실현하기 어렵습니다.

/* 
* Compilation commands: 
* gcc -Wall -Wextra -O2 -o ./bin/share ./share.c 
*  - Optimization enabled, "volatile" is mandatory 
*  - Without "volatile" child1 and child2 indefinite loop 
* 
* gcc -Wall -Wextra -O0 -o ./bin/share ./share.c 
*  - Problem not seen 
* 
* Root cause of the problem is L2 cache, as it is private to core 
*/ 

/* Linux includes */ 
#define _GNU_SOURCE 
#include <sched.h> 
#include <unistd.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 

/* Library includes */ 
#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
    int rc; 
    int shmid; 
    int no_cpu; 
    /* volatile char *shm = NULL; <== uncomment to get rid of the problem */ 
    char *shm = NULL; 
    cpu_set_t cpu; 
    size_t size = 10; 
    pid_t child1, child2; 


    no_cpu = sysconf(_SC_NPROCESSORS_ONLN); 
    if(no_cpu < 3) { 
     printf("ERROR: Minimum 3 CPU cores required\n"); 
     printf("If you have only two CPU's, adjust the CPU_SET accordingly\n"); 
     return -1; 
    } 

    CPU_ZERO(&cpu); 

    shmid = shmget(getpid(), size, IPC_CREAT); 
    if(shmid < 0) { 
     perror("Fail to get shared memory"); 
     return -1; 
    } 

    if((shm = shmat(shmid, NULL, 0)) == (char *)-1) { 
     perror("Fail to attach to shared memory"); 
     return -1; 
    } 

    child1 = fork(); 
    if(child1 == 0) { 
     child2 = fork(); 
     if(child2 == 0) { /* Parent */ 
      CPU_SET(0, &cpu); /* Run on CPU 0 */ 
      rc = sched_setaffinity(getpid(), sizeof(cpu), &cpu); 
      if(rc != 0) { 
       printf("Unable to set affinity to [%d] parent\n", getpid()); 
       kill(child1, SIGTERM); 
       kill(child2, SIGTERM); 
       waitpid(child1, NULL, 0); 
       waitpid(child2, NULL, 0); 
       return -1; 
      } 

      printf("[%d] parent running in [%d]\n", getpid(), sched_getcpu()); 

      *shm = 'a'; 
      waitpid(child1, NULL, 0); 
      waitpid(child2, NULL, 0); 
      shmdt((void *)shm); 
     } 
     else if(child2 > 0) { /* Kid 2 */ 
      CPU_SET(1, &cpu); /* Run on CPU 1 */ 
      rc = sched_setaffinity(getpid(), sizeof(cpu), &cpu); 
      if(rc != 0) { 
       printf("Unable to set affinity to [%d] child2\n", getpid()); 
       return -1; 
      } 
      printf("[%d] child2 running in [%d]\n", getpid(), sched_getcpu()); 

      while(*shm != 'a'); 

      shmdt((void *)shm); 
      exit(0); 
     } 
     else { 
      printf("Fork failed\n"); 
      kill(child1, SIGTERM); 
      waitpid(child1, NULL, 0); 
      return -1; 
     } 
    } 
    else if(child1 > 0) { /* Kid 1*/ 
     CPU_SET(2, &cpu); /* Run on CPU 2 */ 
     rc = sched_setaffinity(getpid(), sizeof(cpu), &cpu); 
     if(rc != 0) { 
      printf("Unable to set affinity to [%d] child1\n", getpid()); 
      return -1; 
     } 
     printf("[%d] child1 running in [%d]\n", getpid(), sched_getcpu()); 

     while(*shm != 'a'); 

     shmdt((void *)shm); 
     exit(0); 
    } 
    else { 
     printf("Fork failed\n"); 
     return -1; 
    } 
    return 0; 
} 
+2

왜'mmap (..., MAP_SHARED, ...)'가 sysV 공유 메모리를 사용하고 있습니까? 그리고 왜'getpid()'가 유효한 sysV'key_t'를 리턴 할 것이라고 기대합니까? 사용하려고하는 기능 중 하나만 맨 페이지로 읽었습니까? – EOF

+2

캐시 관리는 OS의 문제입니다. L2 (또는 다른 레벨) 캐시에는 문제가 없다는 것을 확신 할 수 있습니다. 항상 먼저 다른 사람이 아닌 자신의 편에서 잘못을 검색하십시오! – Olaf

+0

이와 같은 동기화를 위해 공유 메모리를 사용해서는 안됩니다. 이것은 세마포어 또는 두 개의 완벽한 장소입니다. – Riley

답변

0

이것은 C 컴파일러의 최적화 작업 방식입니다.

이 코멘트는 올바른 방향으로 리드이 있어야합니다

/* volatile char *shm = NULL; <== uncomment to get rid of the problem */ 
char *shm = NULL; 

를 루프는 다음과 같습니다 때문에 :

while(*shm != 'a'); 

불변 루프 외부을 같이 메모리로드 작업을 이동합니다 최적화 루프가 아닌 경우 휘도가 인 로딩이 강제 실행되지 않으면 예외입니다.메모리 위치는 이 아니며은 정상 프로그램 흐름 외부에서 변경된 것으로 간주됩니다 (선언되지 않은 경우 volatile).

+0

'volatile'은 멀티 스레딩이나 공유 메모리 다중 처리에 적합하지 않습니다. 주소가없는 플랫폼이나 그렇지 않은 경우 세마포어에서 C11'_Atomic'을 권장합니다. – EOF