2016-08-16 43 views
-2

目的:Linux的在多核處理器3個處理(每個進程在不同的核心上運行)之間共享存儲器/ SMP

我想同步三種不同的過程,所以我想使用在進程之間共享內存。所以我從一個進程中分出了兩個孩子,並在創建孩子之前創建了共享內存段。 我的意圖是在不同的內核中運行子進程和父進程以使其並行執行。所以我使用親和力控制來分配相應的CPU。這兩個孩子都將在無限期等待while循環(在分配的同一個CPU上使用),直到它通過共享內存從父級獲取觸發器。所以當父母寫入一些特定的字符/字符串時,孩子應該出來循環並開始執行其餘的代碼。

問題:

的變量「SHM」即共享內存的變化是不是子進程可見,從不出來while循環。

一些判斷:

我覺得這個問題是因爲它不被無效並提出了處理移動到特定內核後髒的L2緩存。所以核心仍然指向共享內存的舊值。只有當優化級別超過「0」時纔會發生這種情況,即O2。當我強迫它到O0時,那麼問題就看不到了。我對Linux內核和處理器本身的緩存背景不太瞭解。所以我暫時修改了代碼,以便使用「volatile」從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

緩存管理是操作系統的問題。您可以確定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

相關問題