0

Unix C で共有メモリ、セマフォ、およびフォークを使用する際に問題があります。私のセマフォは posix ではありません。共有メモリ 2*sizeof(float) へのポインタを作成します。semctl でセマフォの値を 2 に初期化します。for ループ (i<2) で fork() を実行します。子プロセス (fork() == 0 の場合) では、各子はセマフォで ap 操作を行い (-1)、共有メモリに書き込み、次に av 操作を行い (+1)、終了します。親プロセスは、セマフォで ap 操作 (-2) を実行し、(for ループを使用して) 共有メモリ セグメント全体を読み取り、av 操作 (+2) を実行します。彼は、ゾンビを避けるために終了する前に子プロセスを待機します。出力の問題は、次のようになることです。

 Parent reading 0
 Parent reading 1
 Parent reading 0
 Parent reading 1
 Child writing 0
 Child writing 1

私が取得する必要があるのはいつですか:

 Child writing 0
 Child writing 1
 Parent reading 0
 Parent reading 1

セマフォを 2 ではなく 1 に初期化しようとしましたが、セマフォの値が 2 になることはなく、親プロセスが読み取れないため、プログラムが停止するだけです。

セマフォについて私が理解していることが正しければ、セマフォを 2 に初期化するということは、子プロセスが何も書き込んでいないにもかかわらず、親プロセスが直接読み取ることができることを意味します。この問題を解決するにはどうすればよいですか?

編集: リクエスト後にコードの簡易版を追加しました。エラー チェックを削除し、子供が長さを短くするのを待ちました。

/** OPEN MEMORY **/

int shmid1 = shmget(1990, (size),  IPC_CREAT | 0666 ); 

float * shmPt = (float*)shmat(shmid1, NULL, 0);    

/** CREATE INITIALIZE SEMAPHORE **/   

semun1.val = 2;

int semid = semget(1991, 1, 0666 | IPC_CREAT)

semctl(semid, 0, SETVAL, semun1 )


  /**  CREATE PROCESSES **/
  for ( ii = 0; ii < 2; ++ii) {
    if ((p = fork()) == 0) {

      int semid = semget(1991, 1, 0666);

      struct sembuf p_buf;

      p_buf.sem_num = 0;p_buf.sem_op = -1;p_buf.sem_flg = SEM_UNDO;
      /** LOCK **/ 
      semop(semid, &p_buf,1);
      /** WRITE **/
      shmPt[ii] = RandomFloat;

      v_buf.sem_num = 0;v_buf.sem_op = 1;v_buf.sem_flg = SEM_UNDO;
      /** UNLOCK **/
      semop(semid, &v_buf,1) 

      exit(0);
    }
    else {

      int semid = semget(1991, 1, 0666);

      struct sembuf p_buf;

      p_buf.sem_num = 0;p_buf.sem_op = -2;p_buf.sem_flg = SEM_UNDO;
      /** LOCK **/ 
      semop(semid, &p_buf,1);
      /** READ **/
      for(int j =0;j<2;j++) tabFloat[j] = shmPt[j];

      v_buf.sem_num = 0;v_buf.sem_op = 2;v_buf.sem_flg = SEM_UNDO;
      /** UNLOCK **/
      semop(semid, &v_buf,1) 

    }
}

編集: 私の最終的な目標は、24 人の子供が同じサイズの共有メモリ セグメントに 1 つずつ書き込み、それがいっぱいになったときにのみ、親がすべてを読み取って情報を処理できるようにすることです。さらに、これらすべてを while ループにする必要があります (最初の車が 50 周を完了するまで、1 周を完了するたびにランダムな時間を生成し続ける 24 台の車を想像してください)。

4

1 に答える 1

4

セマフォを誤用しています。一般的な考え方は、セマフォは「現在、このデータを使用できるエンティティ (スレッドなど) の数」をカウントするというものです。カウントを 2 から開始することで、「現在、2 つのスレッドがこれを使用する可能性がある」と言っています。セマフォは、どのエンティティーも、どのように(読み取りと書き込み) かを示すのではなく、いくつの. たとえば、セマフォを使用して、プロデューサー/コンシューマー キュー内の取得可能なアイテムの数をカウントできます。プロデューサーはインクリメントし、コンシューマーはデクリメントします。(もちろん、セマフォにはあらゆる種類の拡張されたフレーバーがあります。これらは「POSIX ではない」と言っています、実際のものではないため、これ以上一般化することは困難です。)

これを説明どおりに機能させる 1 つの方法 (もちろん、実際のコードは説明とは異なる傾向があります) は、セマフォ カウントを 0 から開始し、子をフォークし、セマフォ カウントを見ずに子に書き込み、別の子をフォークし、その子もセマフォ カウントを見ずに書き込み、親にセマフォ (P) を待機させます。つまり、セマフォは「何も通過しない」と言っていますが、子供たちは実際にはそれを見ません。次に、2 つの子はそれぞれ V 操作 (それぞれ +1) を実行します。セマフォが 1 になると、親が開始します。親は、少なくとも 1 つ (ただし、おそらく 1 つだけ) の子結果を見つけることができます。両方の結果が必要な場合、親はすぐに別の P を実行できます。

(ただし、より一般的には、リーダー/ライター ロックまたはミューテックスと条件変数が必要になる場合があります。POSIX スレッドがある場合は、、、、、などを参照しpthread_cond_init()pthread_cond_wait()ください。)pthread_cond_signal()pthread_mutex_init()


あはは、コメントと質問編集から、惨めな System V 共有メモリとセマフォ インターフェイスを使用していることがわかります。

  • あなたは本当にそれで立ち往生していますか?私の意見では、POSIXスレッドの方が優れています(そして一般的に軽量です)。
  • 共有メモリをどのように編成するつもりですか? 各車に独自のラップ タイム領域があり、表示スレッド/プロシージャのみと共有されている場合、ロック競合が少なくなる可能性があります。1 つのプロデューサー (車) と 1 つのコンシューマ (表示スレッド/プロシージャ) がありますが、24 のそのようなロック ( 1台につき1台)。すべての車が 1 つの共有メモリ領域をディスプレイ スレッド/プロシージャと共有する場合、必要なロックは 1 つだけですが、よりアクティブになります。どちらが「より良い」かは、あなたが何をしているかによって異なります。
  • また、「一部の車が 50 周を終える」のを待ちたい場合は、各車に独自のプライベート (またはディスプレイと共有されている可能性がある) カウンターと、「50 周に達した車の数」をカウントする 1 つのセマフォを用意することを検討してください。 "。各車は単純にカウントアップし、50 に達すると、カウントセマフォも (1 回) インクリメントします。

最終的な(私は願っています)編集:小さな問題を修正した後、最後に残ったものは、SEM_UNDO各子プロセスでの使用でしたexit. SEM_UNDOプロセスの終了時に適用されるバランス調整値を記録するため、セマフォはカウントアップしますが、すぐにカウントダウンし、親は決して発生しない別の V を待機します。

于 2013-05-26T18:44:24.393 に答える