我目前正在研究用 C 语言进行多线程处理,但是我不太理解我们的命名管道 excersize。
我们期望实现一个文件搜索系统的实现,该系统查找文件并添加到一个进程的缓冲区中,第二个进程应该从第一个进程的线程中获取文件名,找到该文件内的搜索查询并将位置返回给第一个进程管道。我几乎完成了所有这些,但我很困惑如何在两个进程之间进行通信。
这是我进行通信的代码:
main.c
void *controller_thread(void *arg) {
pthread_mutex_lock(&index_mutex);
int index = t_index++; /*Get an index to thread*/
pthread_mutex_unlock(&index_mutex);
char sendPipe[10];
char recvPipe[10];
int fdsend, fdrecv;
sprintf(sendPipe, "contrl%d", (index+1));
sprintf(recvPipe, "minion%d", (index+1));
mkfifo(sendPipe, 0666);
execlp("minion", "minion", sendPipe, recvPipe, (char*) NULL);
if((fdsend = open(sendPipe, O_WRONLY|O_CREAT)) < 0)
perror("Error opening pipe");
if((fdrecv = open(recvPipe, O_RDONLY)) < 0)
perror("Error opening pipe");
while(1) {
char *fileName = pop(); /*Counting semaphore from buffer*/
if(notFile(fileName))
break;
write(fdsend, fileName, strlen(fileName));
write(fdsend, search, strlen(search));
char place[10];
while(1) {
read(fdrecv, place, 10);
if(notPlace(place)) /*Only checks if all numeric*/
break;
printf("Minion %d searching %s in %s, found at %s\n", index,
search, fileName, place);
}
}
}
从我找到的网上资源来看,我认为这是在main中处理fifo的方式。我尝试编写一个测试 Minion 只是为了确保它能正常工作,所以这里是
minion.c
int main(int argc, char **argv) {
char *recvPipe = argv[1];
char *sendPipe = argv[2];
char fileName[100];
int fdsend, fdrecv;
return 0;
fdrecv = open(recvPipe, O_RDONLY);
mkfifo(sendPipe, 0666);
fdsend = open(sendPipe, O_WRONLY|O_CREAT);
while(1) {
read(fdrecv, fileName, 100);
write(fdsend, "12345", 6);
write(fds, "xxx", 4);
}
return 0;
}
当我以这种方式运行时,如果我将打开模式更改为 O_NONBLOCK,线程就会被阻塞并且不会打印任何响应。然后它打印“错误打开管道,没有这样的设备或地址”错误,所以我知道不知何故我无法打开minion内的recvPipe,但我不知道错误是什么
最佳答案
您的代码存在的问题之一是对 execlp()
的使用存在明显的误解。 。成功后,此函数不会返回,因此其后面的代码将永远不会被执行。普通一个fork()
首先执行 execlp()
在子进程中,如果 execlp()
则确保让子进程终止失败。父进程最终可能也需要等待 fork 的子进程。
此外,每个进程都会通过 O_CREAT
,这很奇怪,而且可能是不受欢迎的。当它尝试打开 FIFO 的写端时标记。应该是没有必要的,因为每个人都刚刚创建了 mkfifo()
的 FIFO。 。即使在mkfifo()
的情况下失败或者某个其他进程在打开它之前将其删除,您不想使用 O_CREAT
打开它因为这会给你一个常规文件,而不是 FIFO。
修复 execlp()
后问题,你也会有竞争条件。父进程依赖子进程来创建 FIFO 之一,但不会等待该进程这样做。如果父级在子级完成其 mkfifo()
之前达到其打开尝试,您将不会获得所需的行为。 .
我建议让父进程在创建子进程之前创建两个 FIFO。子级和父级必须合作,首先打开一个 FIFO 的两端,然后再打开另一个 FIFO 的两端。一个打开以进行读取的操作将被阻塞,直到另一个打开相同的 FIFO 进行写入为止。
或者您可以使用普通(匿名)管道(请参阅 pipe()
)而不是 FIFO。它们在两端都是开放的,并且对于通过继承相关的进程之间的通信来说更自然。
无论如何,一定要检查函数调用的返回值。几乎所有这些函数都可能失败,预先检测并处理它比在您错误地假设每个调用都成功时理清可能形成的困惑要好得多。
关于C fifo 保持阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43824458/