2016-08-16 21 views
-2

目的:Linuxの共有メモリ

私は、3つの異なるプロセスを同期させたいので、私はプロセス間で共有メモリを使用するのではと思いました。だから私は1つのプロセスから2つの子供をフォークし、子供を作成する前に共有メモリセグメントを作成しました。 私の意図は、子プロセスと親プロセスを異なるコアで実行して、並列実行させることです。だから私はアフィニティコントロールを使用して、対応するCPUを割り当てました。両方の子供は、共有メモリを介して親からトリガを得るまで、無限ループwhileループ(割り当てられた同じCPUで消費される)で待機します。したがって、親がいくつかの特定の文字/文字列を書き込むとき、子はループを抜けて残りのコードの実行を開始する必要があります。

問題:

共有メモリすなわち変数「SHM」での変更は子プロセスには見えないし、決してwhileループから出てきません。

いくつかの判断:

私は、問題は、無効にして、特定のコアにプロセスを移動した後、汚れ行われていないL2キャッシュのある感じ。したがって、コアは依然として共有メモリの古い値を参照しています。これは、最適化レベルがO2よりも「0」以上である場合にのみ起こる。私が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'を返すと思いますか?使用しようとしている機能のマニュアルページを1つ読んだことがありますか? – EOF

+2

キャッシュ管理はOSの問題です。 L2(または他のレベルの)キャッシュに問題がないことを確かめることができます。いつも、まずあなたの側の欠陥を探してください。 – Olaf

+0

あなたは本当にこのような同期のために共有メモリを使用すべきではありません。これはセマフォーまたは2つのための完全な場所です。 – Riley

答えて

0

これは、Cコンパイラの最適化の仕組みです。

このコメントは、あなたは正しい方向にリードを持っている必要があります。

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

をあなたのループは次のようになりますので:

while(*shm != 'a'); 

不変ループとしてメモリロード操作を移動しますオプティマイザループは、volatileを使用して、読み込みが強制的に所定の位置にとどまる場合を除きます。メモリの場所は、ではありません。は、通常のプログラムフローの外側で変更されるはずです(volatileと宣言されていない場合)。

+0

'volatile'はマルチスレッドや共有メモリのマルチプロセッシングには適していません。私はC11 '_Atomic'をアドレスフリーであるプラットフォームやそうでなければセマフォーに置くことをお勧めします。 – EOF