有 5 个子进程和 1 个父进程(为了简化,我们只使用 1 个子进程)。一些计算在子进程中进行,之后它们必须将信息传递给父进程。我使用 TAILQ 队列进行消息传递。 问题是运行下面的程序会导致完全空的输出。尽管队列是在分叉之前初始化的,但我们得到的结果就好像同一队列的两个实例彼此不联系。如果您从子进程调用 TAILQ_FIRST,则一切正常。 如何同步队列?
#define _SVID_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/queue.h>
struct message
{
int num;
char status;
TAILQ_ENTRY(message) queue_entry;
};
struct message_queue
{
TAILQ_HEAD(head_t, message) head;
} queue;
int main()
{
TAILQ_INIT(&queue.head);
pid_t pid;
pid = fork();
if (!pid) // child process
{
while(1)
{
struct message* p = malloc(sizeof(struct message));
p->num = 1;
p->status = 's';
TAILQ_INSERT_TAIL(&queue.head, p, queue_entry);
}
}
else // parent process
{
while (1)
{
struct message* p = TAILQ_FIRST(&queue.head);
if (p)
{
TAILQ_REMOVE(&queue.head, p, queue_entry);
}
if (p)
{
printf("Num %d and status %c", p->num, p->status);
free(p);
}
}
}
return 0;
}
扩展我的评论; TAILQ 机制仅适用于单个进程,不能跨父/子进程。
我们得到好像同一队列的两个实例彼此不联系。
是的,您理解正确。
当您调用
fork()
时,它实际上创建了与第一个进程相同的第二个进程,其中包含所有程序和内存区域的副本,唯一的区别是 pid
变量的返回值:它在子进程中为零,并且父级中的非零(好吧,<0 is an error as well).
这意味着在分叉时,现在有两个队列的私有副本,并且每个进程都在其上“正确”操作,但没有操作另一端的协作进程。
我清楚地记得我试图理解单个函数以这种方式运行的概念:-)
在您的示例中,子进程能够一遍又一遍地添加消息,但没有消费者。父母正在等待某件事发生,但它永远不会发生。
如果您的任务仅限于父进程和子进程相互通信,那么管道是一个很好的机制,但如果您需要更一般的进程间通信,那么 POSIX 消息队列是一个公平的选择,但可能还有其他选择。