목적 :리눅스 공유 메모리/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;
}
왜'mmap (..., MAP_SHARED, ...)'가 sysV 공유 메모리를 사용하고 있습니까? 그리고 왜'getpid()'가 유효한 sysV'key_t'를 리턴 할 것이라고 기대합니까? 사용하려고하는 기능 중 하나만 맨 페이지로 읽었습니까? – EOF
캐시 관리는 OS의 문제입니다. L2 (또는 다른 레벨) 캐시에는 문제가 없다는 것을 확신 할 수 있습니다. 항상 먼저 다른 사람이 아닌 자신의 편에서 잘못을 검색하십시오! – Olaf
이와 같은 동기화를 위해 공유 메모리를 사용해서는 안됩니다. 이것은 세마포어 또는 두 개의 완벽한 장소입니다. – Riley