【问题标题】:Why is my producer-consumer blocking?为什么我的生产者-消费者阻塞?
【发布时间】:2012-11-14 20:51:47
【问题描述】:

我的代码在这里:http://pastebin.com/Fi3h0E0P

这是输出

0
Should we take order today (y or n): y
Enter order number: 100
More customers (y or n): n

Stop serving customers right now. Passing orders to cooker:
There are total of 1 order(s)
1
Roger, waiter. I am processing order #100

目标是服务员必须接受订单,然后将它们交给厨师。服务员必须等待厨师完成所有比萨饼,送出比萨饼,然后接受新订单。

我在之前的帖子here 中询问了 P-V 的工作原理。

我认为这与\n 消费无关?我尝试了wait() 的各种组合,但都不起作用。

我在哪里做错了?

主要部分在这里:

//Producer process
 if(pid > 0)
 {
    while(1)
    {
      printf("0");
      P(emptyShelf); // waiter as P finds no items on shelf;
      P(mutex); // has permission to use the shelf
      waiter_as_producer();
      V(mutex); // cooker now can use the shelf
      V(orderOnShelf); // cooker now can pickup orders

      wait();
      printf("2");
      P(pizzaOnShelf);
      P(mutex);
      waiter_as_consumer();
      V(mutex);
      V(emptyShelf);
      printf("3 ");
    }
 }
    if(pid == 0)
    {
     while(1)
    {
     printf("1");
     P(orderOnShelf); // make sure there is an order on shelf
     P(mutex); //permission to work
     cooker_as_consumer(); // take order and put pizza on shelf
     printf("return from cooker");
     V(mutex); //release permission
     printf("just released perm");
     V(pizzaOnShelf); // pizza is now on shelf
     printf("after");
     wait();
     printf("4");

    }
  }

所以我想这是执行路径: 进入waiter_as_producer,然后进入子进程(cooker),然后将控制权交还给父进程,完成waiter_as_consumer,切换回子进程。这两个等待切换回父级(就像我说我尝试了所有可能的 wait() 组合......)。

【问题讨论】:

  • 各个进程阻塞了哪些等待操作?
  • 另外,wait() 是做什么的?如果它是 POSIX 函数,那么它应该是没有必要的 - P() 并且也许 V() 应该等待。
  • 这是头文件pastebin.com/4Jse4bRg,最后定义了P,V。
  • 添加一些 \n 到 printf 字符串。标准输出是行缓冲的。
  • @User007 这是对我有用的要点:gist.github.com/4075391

标签: c algorithm unix semaphore producer-consumer


【解决方案1】:
  • 更改为#define PERMS (0)(它不是八进制文件模式掩码!)
  • 删除所有wait();s
  • 按 sizeof 缩放大小:if((shmid=shmget(1000,sizeof (int) * BUFSIZE,IPC_CREAT | PERMS)) < 0) 和其他(大小以 semsize/pagesize 为模放大,但无论如何使用正确的大小是一个好习惯)

在这里解决了问题。

整个想法是:您不需要等待; {producer,consumer} 之一将在某处的 P() 上被阻止:

来自 P():

sb.sem_flg = 0; /* blocking call */
    if (semop(sid, &sb, 1) == -1)
        perror("semop");

此外:wait(&status) 至少需要一个参数。 (并且您可能需要其他等待函数之一,例如 wait3() 或 waitpid() )

除此之外:

  • 我会在共享对象的声明前加上“volatile”:volatile int *buff;
  • main() 应该返回 int,没有值的返回是错误的(c99 之前)
  • 大多数指针操作都很笨拙:order = buffer[i];order = *(buffer+i); 相同,但更具可读性。

【讨论】:

  • 我猜标题中的内容是由讲师提供的。我的操作系统模块也有一个无意义的 SysV IPC 包装器。 (操作系统教师在教授课程时似乎是一种做法,就好像他们希望学生必须在 pre-POSIX 系统上工作一样。)
  • 可以看作是对 RTFM 的练习。
  • 更像是一种深奥的练习。放弃该 API 是有原因的,因为它使用起来很烦人。如果你想让学生使用 RTFM,你不会给他们一个带有包装函数的标题。正如您在答案中指出的那样,实际上已损坏。 (至少我不会。我会将人们指向 POSIX API 的文档,并使用这些调用而不是 PV 来教授课程。)
  • 大家好。非常感谢。我完成了我的工作。我接受了你的建议,wildplasser。我不是那种依赖外援的人。我试图自己解决这个问题,但有时当截止日期临近并且我不知道我的 C 代码出了什么问题时,我不得不寻求帮助。但我学会了。感谢你们俩。下一步是让 codereview 中的人告诉我我的实现是好的还是完全愚蠢的。显然这是一些非常低级的东西,即使是代码也很难理解 O_O。
猜你喜欢
  • 1970-01-01
  • 2014-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
相关资源
最近更新 更多