1

我目前正在玩信号量并试图理解它们。我正在尝试遵循一个教程,该教程要求我编辑示例代码以使程序运行两个进程,这两个进程轮流将歌词输出到歌曲中(“桶中有一个洞”)。

我的问题是,当我在程序中添加更多歌曲行时,这些过程不会交替,但是当只有两行时它们可以正常工作。

一个进程处理 Liza 的部分,另一个处理 Henry 的部分。这是我的代码:

#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

信号量不强制关键部分的调度或排序,它们仅用于资源锁定。你想要的可以这样想:

给定一组有序/排序的数据和两个负责将其内容打印到流的“工人”:

  1. 每个工人“等待”轮到他们
  2. 它获取一个数据(例如歌曲中的一行)
  3. 它将数据打印到标准输出
  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关键字?它告诉编译器不要将变量存储在寄存器中,每次都必须从内存中读取它,因为它可能会被外部修改(在这种情况下是由另一个线程)。我还为这两种状态添加了两个常量,只是为了使代码更易于阅读。我你想要,你可以用一个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 回答