1

私は現在、セマフォをいじって理解しようとしています。サンプルコードを編集して、歌詞を曲に出力する2つのプロセスを順番に実行するプログラムを取得するように求めるチュートリアルに従おうとしています(「バケットに穴があります」)。

私の問題は、プログラムに曲の行を追加してもプロセスが交互にならないことですが、行が2行しかない場合は正しく機能します。

1つのプロセスはリザの部分を処理し、別のプロセスはヘンリーの部分を処理します。これは私のコードです:

#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>

#define KEY 87654 //Unique semaphore key

int main()
{
  int id; /* Number by which the semaphore is known within a program */

  union semun {
    int val;
    struct semid_ds *buf;
    ushort * array;
  } argument;

  argument.val = 1;

  /* Create the semaphore with external key KEY if it doesn't already 
     exists. Give permissions to the world. */
  id = semget(KEY, 1, 0666 | IPC_CREAT);

  /* Always check system returns. */      
  if(id < 0) {
      fprintf(stderr, "Unable to obtain semaphore.\n");
      exit(0);
  }

  /* What we actually get is an array of semaphores. The second 
     argument to semget() was the array dimension - in our case
     1. */

  /* Set the value of the number 0 semaphore in semaphore array
     # id to the value 0. */      
  if( semctl(id, 0, SETVAL, argument) < 0) {
      fprintf( stderr, "Cannot set semaphore value.\n");
  } else {
      fprintf(stderr, "Semaphore %d initialized.\n", KEY);
  }

  int pid=fork();

  if(pid) {
    struct sembuf operations[1];
    int retval; /* Return value from semop() */

    /* Get the index for the semaphore with external name KEY. */
    id = semget(KEY, 1, 0666);

    if(id < 0){
      /* Semaphore does not exist. */

      fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
      exit(0);
    }
    operations[0].sem_num = 0;
    /* Which operation? Subtract 1 from semaphore value : */
    operations[0].sem_op = -1;
    /* Set the flag so we will wait : */   
    operations[0].sem_flg = 0;

    while(1){
      //Process 1

      //wait
      operations[0].sem_op = -1;
      retval = semop(id, operations, 1);

      //critical section
      printf("Then mend it, dear Henry, dear Henry, dear Henry, \n");
      printf("Then mend it, dear Henry, dear Henry, mend it. \n");

      fflush(stdout);
      int stime=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stime);
      sleep(stime);

      printf("With a straw, dear Henry, dear Henry, dear Henry, \n");
      printf("With a straw, dear Henry, dear Henry, with a straw. \n");

      fflush(stdout);

      int stim1e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim1e);
      sleep(stim1e);

      printf("Then cut it, dear Henry, dear Henry, dear Henry, \n");
      printf("Then cut it, dear Henry, dear Henry, cut it. \n");

      fflush(stdout);
      int stim2e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim2e);
      sleep(stim2e);

      printf("With a knife, dear Henry, dear Henry, dear Henry, \n");
      printf("With a knife, dear Henry, dear Henry, with a knife. \n");
      fflush(stdout);

      int stim3e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim3e);
      sleep(stim3e);

      printf("Then sharpen it, dear Henry, dear Henry, dear Henry \n");
      printf("Then sharpen it, dear Henry, dear Henry, sharpen it. \n");

      fflush(stdout);
      int stim4e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim4e);
      sleep(stim4e);

      printf("On a stone, dear Henry, dear Henry, dear Henry, \n");
      printf("On a stone, dear Henry, dear Henry, a stone. \n");

      fflush(stdout);
      int stim5e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim5e);
      sleep(stim5e);

      printf("Well wet it, dear Henry, dear Henry, dear Henry, \n");
      printf("Well wet it, dear Henry, dear Henry, wet it. \n");

      fflush(stdout);
      int stim6e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim6e);
      sleep(stim6e);

      printf("try water, dear Henry, dear Henry, dear Henry, \n");
      printf("try water, dear Henry, dear Henry, water. \n");

      fflush(stdout);
      int stim7e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim7e);
      sleep(stim7e);

      printf("In a bucket, dear Henry, dear Henry, dear Henry, \n");
      printf("In a bucket, dear Henry, dear Henry, a bucket. \n");

      fflush(stdout);
      int stim8e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim8e);
      sleep(stim8e);

      printf("Use your head, then! dear Henry, dear Henry, dear Henry, \n");
      printf("Use your head, then! dear Henry, dear Henry, use your head! \n");

      fflush(stdout);

      operations[0].sem_op = 1;
      //signal
      retval = semop(id, operations, 1);

    }
  }else{
    //Process 2
    struct sembuf operations[1];
    int retval; /* Return value from semop() */
    /* Get the index for the semaphore with external name KEY. */
    id = semget(KEY, 1, 0666);
    if(id < 0){
      /* Semaphore does not exist. */

      fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
      exit(0);
    }
    operations[0].sem_num = 0;
    /* Which operation? Subtract 1 from semaphore value : */
    operations[0].sem_op = -1;
    /* Set the flag so we will wait : */   
    operations[0].sem_flg = 0;

    while(1){



      //wait
      operations[0].sem_op = -1;
      retval = semop(id, operations, 1);

      //critical section

      printf("There's a hole in the bucket, dear Liza, dear Liza, \n");
      printf("There's a hole in the bucket, dear Liza, a hole. \n");

      fflush(stdout);
      int stim9e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim9e);
      sleep(stim9e);

      printf("With what shall I mend it, dear Liza, dear Liza? \n");
      printf("With what shall I mend it, dear Liza, with what? \n");
      fflush(stdout);

      int stim0e=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stim0e);
      sleep(stim0e);

      printf("The straw is too long, dear Liza, dear Liza, \n");
      printf("The straw is too long, dear Liza, too long, \n");

      fflush(stdout);
      int stimae=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimae);
      sleep(stimae);

      printf("The knife is too dull, dear Liza, dear Liza, \n");
      printf("The knife is too dull, dear Liza, too dull. \n");

      fflush(stdout);
      int stimse=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimse);
      sleep(stimse);

      printf("On what shall I sharpen it, dear Liza, dear Liza? \n");
      printf("On what shall I sharpen it, dear Liza, on what? \n");

      fflush(stdout);
      int stimde=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimde);
      sleep(stimde);

      printf("The stone is too dry, dear Liza, dear Liza, \n");
      printf("The stone is too dry, dear Liza, too dry. \n");

      fflush(stdout);
      int stimwe=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimwe);
      sleep(stimwe);

      printf("With what shall I wet it, dear Liza, dear Liza? \n");
      printf("With what shall I wet it, dear Liza, with what? \n");

      fflush(stdout);
      int stimqe=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimqe);
      sleep(stimqe);

      printf("In what shall I fetch it, dear Liza, dear Liza? \n");
      printf("In what shall I fetch it, dear Liza, in what? \n");

      fflush(stdout);
      int stimee=2+(rand()/(float)(RAND_MAX))*4;
      printf("Sleeping for %d secs\n",stimee);
      sleep(stimee);

      printf("There's a hole in my bucket, dear Liza, dear Liza \n ");
      printf("There's a hole in my bucket, dear Liza, a hole. \n ");
      fflush(stdout);

      //signal
      operations[0].sem_op = 1;
      retval = semop(id, operations, 1);

    }

  }

}
4

2 に答える 2

0

セマフォは、クリティカルセクションのスケジューリングや順序付けを強制するものではなく、リソースのロックのみを目的としています。あなたが望むものは次のように考えることができます:

順序付け/ソートされたデータセットと、コンテンツをストリームに出力するタスクを実行する2人の「ワーカー」があるとします。

  1. 各労働者は自分の順番を「待つ」
  2. 1つのデータを取得します(たとえば、曲から1行)
  3. データムをstdoutに印刷します
  4. それが完了し、スリープ/待機することを他のワーカーに示します

すべてのステップ1〜4をクリティカルセクションと見なす場合、セマフォはこの問題を解決するのに十分です。つまり、「リソース」はa)データのストレージとb)出力ストリームの両方です。リソースロックのためのセマフォの使用例を確認するには、食事する哲学者の問題を参照してください。

于 2013-03-25T08:44:03.097 に答える
0

スレッドは、ラインの配信が終了したことをスレッドHenryに通知する必要があります。Lizaこれを行う簡単な方法は、変数を使用することです。

const int HENRY_DONE = 0;
const inte LIZA_DONE = 1;
volatile int flag = HENRY_DONE;

キーワードに気づきましたvolatileか?変数をレジスタに格納しないようにコンパイラに指示します。外部で(この場合は他のスレッドによって)変更される可能性があるため、毎回メモリから読み取る必要があります。また、コードを読みやすくするために、2つの状態に2つの定数を追加しました。代わりに使用できますenum。これにより、コードが少しきれいになります(また、誰かがコード行を書く可能性も低くなりますflag = -32)。

  //critical section
  printf("Then mend it, dear Henry, dear Henry, dear Henry, \n");
  printf("Then mend it, dear Henry, dear Henry, mend it. \n");

  fflush(stdout);

  flag = LIZA_DONE;   // Hand over to Henry
  do {
    sleep(1); // If we don't sleep at all, there will be a busy wait. If you want to sleep for shorter than 1 s use usleep (located in `unistd.h`).
  } until (flag == HENRY_DONE);  // Wait for Henry to complete his next line.
  printf("With a straw, dear Henry, dear Henry, dear Henry, \n");
  printf("With a straw, dear Henry, dear Henry, with a straw. \n");

ヘンリーの部分についても同じようにします。

ノート:

上記のソリューションでは、flagがLIZAとHENRYの両方にアクセス可能なメモリに配置されている必要があります。スレッドを使用する場合はそのまま動作しますが、使用する場合は共有メモリforkに配置する必要があります(例)flag

于 2013-03-26T09:07:21.803 に答える