我正在尝试制定一个简单的生产者 - 消费者计划。我有这段代码:
//global variable g_lastImage is declared as:
volatile int g_lastImage = 0;
void producer(void) {
int i = 0;
while (1) {
sem_wait(&g_shm->PSem);
printf("I:%d\n",i);
if (i == 5) {
g_lastImage = 1;
printf("It's time to say goodbye!\n");
sem_post(&g_shm->ChSem);
return;
}
printf("producing\n");
i++;
sem_post(&g_shm->ChSem);
}
}
void consumer(void) {
while (1) {
sem_wait(&g_shm->ChSem);
if (g_lastImage) {
printf("Bye!\n");
return;
}
printf("consuming\n");
sem_post(&g_shm->PSem);
}
}
int main() {
alloc(); /*allocates shared memory and two semaphores,
ChSem on initial counter value 0 and PSem on value 1*/
int processes = 1; //let's start with one process only just for now
int id = 0, i = 0, status;
for (i = 0; i < processes; i++) {
id = fork();
if (id < 0) {
perror ("error\n");
exit(1);
} else if (id == 0) {
consumer();
printf("child exits\n");
exit(0);
}
}
producer();
for (i = 0; i < processes; ++i) {
wait(&status);
}
return 1;
}
不幸的是,这段代码以死锁结束。我有这个输出:
I:0
producing
consuming
I:1
producing
consuming
I:2
producing
consuming
I:3
producing
consuming
I:4
producing
consuming
I:5
It's time to say goodbye!
consuming
//deadlock - nothing written
请注意“再见!”不是写的。另一方面,额外的“消费”是。这个解决方案有什么问题?使用全局变量检测结束不行吗?无法弄清楚......
感谢您的任何想法。
修改 根据您的建议,我将局部变量的分配更改为volatile并添加'\ n',但问题仍然存在。
答案 0 :(得分:3)
您也必须分享您的旗帜,这可以按照您的预期运作:
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/mman.h>
struct Shared
{
sem_t PSem ;
sem_t ChSem ;
int g_lastImage ;
} * g_shm ;
void producer(void) {
int i = 0;
while (1) {
sem_wait(&g_shm->PSem);
printf("I:%d\n",i);
if (i == 5) {
g_shm->g_lastImage = 1;
printf("It's time to say goodbye!\n");
sem_post(&g_shm->ChSem);
return;
}
printf("producing\n");
i++;
sem_post(&g_shm->ChSem);
}
}
void consumer(void) {
while (1) {
sem_wait(&g_shm->ChSem);
if (g_shm->g_lastImage) {
printf("Bye!\n");
return;
}
printf("consuming\n");
sem_post(&g_shm->PSem);
}
}
int main()
{
g_shm = mmap( NULL , sizeof( struct Shared ) , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS , -1 , 0 );
sem_init( & g_shm->PSem , 1 , 1 );
sem_init( & g_shm->ChSem , 1 , 0 );
g_shm->g_lastImage = 0 ;
int processes = 1;
int id = 0, i = 0, status;
for (i = 0; i < processes; i++)
{
id = fork();
if (id < 0) {
perror ("error\n");
exit(1);
} else if (id == 0) {
consumer();
printf("child exits\n");
exit(0);
}
}
producer();
for (i = 0; i < processes; ++i)
{
wait(&status);
}
return 1;
}
答案 1 :(得分:1)
volatile在这里不会帮助你,因为你分叉了你的进程。这将导致g_lastImage的副本,因此调用producer()的父进程将更改其自己的g_lastImage值,而子进程(在fork获取其自己的变量副本)将始终具有g_lastImage == 0,因此你最终陷入了僵局。您可能只是将g_lastImage的分配插入到信号量的分配中,因为您似乎正确地分配它们以在poth进程中使用它们;)