我已经实现了一个基于共享内存的管道,当我
尝试使用 main
程序调用 fork
。
主要内容如下:
# include "my_shm_piper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <sys/mman.h>
int main()
{
int spd[2], pid, rb;
char buff[4096];
fork(); // that fork is okay , but if we put it after initPipe() , there's a deadlock
initPipe();
if (my_pipe(spd) < 0)
{
perror("my_pipe");
exit(1);
}
if (fork())
{
rb = my_read(spd[0], buff, sizeof(buff));
if (rb > 0)
write(1, buff, rb);
}
else
{
my_write(spd[1], "hello world!\n", sizeof("hello world!\n"));
}
my_close(spd[0]);
my_close(spd[1]);
removePipe();
return 0;
}
正在使用共享内存库实现的匿名管道。
当我如上所述输入 fork()
的 1st
命令时,我的程序将按预期工作,所有 hello-world
>-s 被呈现。
但是当我将 fork
放在 initPipe()
之后时,出现死锁,并且程序挂起:
int main()
{
int spd[2], pid, rb;
char buff[4096];
initPipe();
fork(); // now the fork() is after the initialization ,and we have a deadlock
if (my_pipe(spd) < 0)
{
perror("my_pipe");
exit(1);
}
// from here the same as above
}
我认为 fork() 的初始化阶段只发生一次,而不是
两次,如第一个 main()
。
我猜写作/阅读阶段有问题,但我看不出来 找到确切的来源。
非常感谢您在此事上的帮助
谢谢
编辑:
H.文件中的结构:
struct PipeShm
{
int init;
int flag;
sem_t *mutex;
char * ptr1;
char * ptr2;
int status1;
int status2;
int semaphoreFlag;
};
这是 initPipe:
int initPipe()
{
if (!myPipe.init)
{
myPipe.mutex = mmap (NULL, sizeof *myPipe.mutex, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (!sem_init (myPipe.mutex, 1, 1))
{
myPipe.init = TRUE;
}
else
perror ("initPipe");
}
return 1; // always successful
}
这是 my_pipe():
int my_pipe(int spd[2])
{
spd[0] = shmget(2009, SHMSIZE, 0); // for reading
spd[1] = shmget(2009, SHMSIZE, 0666 | IPC_CREAT); // for writing
if (spd[0] == -1 || spd[1] == -1)
{
perror("shmget");
exit(EXIT_FAILURE);
return -1;
}
return 1;
}
这是阅读内容:
ssize_t my_read(int spd, void *buf, size_t count)
{
char array[4096];
memset (array, '\0', 4096);
ssize_t returnVal = 0;
sem_wait (myPipe.mutex);
int sval;
sem_getvalue (myPipe.mutex, &sval);
printf ("my_read - wait %d\n", sval);
if (sem_wait (myPipe.mutex))
perror ("sem_wait");
printf ("my_read - proceed\n");
if (myPipe.flag == FALSE)
{
myPipe.ptr1 = shmat (spd, NULL, 0); // attaching the segment
if (myPipe.ptr1 == (void *) -1)
error_out ("shmat");
strncpy (array, myPipe.ptr1, count);
array[count] = '\0';
returnVal = strlen (array);
buf = (void *) array;
printf ("Output:%s", array);
}
else if (myPipe.flag == TRUE)
{
const size_t region_size = sysconf (_SC_PAGE_SIZE);
myPipe.ptr1 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
if (myPipe.ptr1 == (void *) -1)
error_out ("mmap");
strncpy (array, myPipe.ptr1, count);
array[count] = '\0';
returnVal = strlen (array);
buf = (void *) array;
printf ("Output:%s", array);
}
return returnVal;
}
这是写作:
ssize_t my_write(int spd, const void *buf, size_t count)
{
ssize_t returnVal = 0;
sleep(1); // debug to ensure that read goes first for testing.
if (myPipe.flag == FALSE)
{
myPipe.ptr2 = shmat (spd, NULL, 0); // attaching the segment
if (myPipe.ptr2 == (void *) -1)
error_out ("shmat");
char *d = (char *) buf;
returnVal = snprintf (myPipe.ptr2, count, "%s", d);
}
else
{
const size_t region_size = sysconf (_SC_PAGE_SIZE);
// Map the region into memory.
myPipe.ptr2 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
if (myPipe.ptr2 == MAP_FAILED)
error_out ("mmap");
char *d = (char *) buf;
returnVal = snprintf (myPipe.ptr2, count, "%s", d);
}
sem_post (myPipe.mutex);
return returnVal;
}
进程像这样挂起 - 在第二个主进程中(这是控制台上的输出):
my_read - wait 0
my_read - proceed
Output:hello world!
// here it just gets stuck
在第一个 main 中,控制台的输出是:
my_read - wait 0
my_read - wait 0
my_read - proceed
my_read - proceed
Output:hello world!
Output:hello world!
// here the program is done , the end
最佳答案
啊。有点棘手,但我很无聊才弄清楚。
基本上,你的等待和发帖是不平衡的。如果您查看 read() 函数,您会执行两次等待:
sem_wait (myPipe.mutex);
// some more code
if (sem_wait (myPipe.mutex))
perror ("sem_wait");
但是你的 write 函数只执行一篇文章。
但是如果 fork 发生在 initPipe()
之前,为什么它会起作用? ?因为您将信号量初始化为 1:
if (!sem_init (myPipe.mutex, 1, 1))
由于您在 init 之前 fork ,因此您有两个不同的信号量,其值为 1;每个人都会收到一个帖子并等待两次,所以你没问题。
在另一种情况下,您有一个值为 1 的信号量,它将接收两个帖子和四个等待。 1 + 2 < 4
,这样您的一位读者就会坚持 sem_wait
.
顺便说一句,这是一种相当复杂的写作方式 pipe(2)
.
关于c - 调用fork()时程序陷入死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11703268/