我目前正在使用C语言进行多线程处理,但是我对命名管道的优缺点有些不太了解。
我们期望执行文件搜索系统,找到文件并添加到具有一个进程的缓冲区,第二个进程应从第一个进程中获取文件名,在该文件中找到搜索查询并将位置返回到第一个进程管。我做了几乎全部但是我很困惑如何在两个进程之间进行通信。
这是我进行沟通的代码:
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);
}
}
}
从我发现的在线资源中,我认为这是处理主要内部的fifo的方法。我试着写一个测试小兵只是为了确保它有效,所以这里是
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更改为open模式,则线程会被阻塞并且不会响应。然后打印&#34;错误打开管道没有这样的设备或地址&#34;错误,所以我知道不知何故我不能打开里面的recvPipe,但我不知道这是什么错误
答案 0 :(得分:1)
您的代码存在的问题是对execlp()
的使用存在明显的误解。成功时,此函数不会返回,因此永远不会执行它后面的代码。首先是一个fork()
,然后在子进程中执行execlp()
,确保在execlp()
失败时终止子进程。父进程可能还需要最终等待分叉的子进程。
此外,当尝试打开FIFO的写端时,每个进程都会传递O_CREAT
标志,这很奇怪,也可能是不可取的。它应该是不必要的,因为每个人刚刚用mkfifo()
创建了FIFO。即使在mkfifo()
失败或某个其他进程在打开之前将其删除的情况下,您也不希望使用O_CREAT
打开,因为这将获得常规文件,而不是FIFO。 / p>
解决execlp()
问题后,您还会遇到竞争条件。父进程依赖于子进程创建其中一个FIFO,但不等待该进程执行此操作。如果父级在子级完成mkfifo()
之前达到其打开尝试,您将无法获得所需的行为。
我建议在创建子进程之前让父进程创建两个 FIFO。孩子和家长必须通过打开一个FIFO的两端进行合作,然后再打开另一个FIFO的两端。打开的读取将被阻塞,直到另一个打开相同的FIFO进行写入。
或者您可以使用普通(匿名)管道(请参阅pipe()
)而不是FIFO。这些是在两端创建的,它们对于通过继承相关的进程之间的通信更自然。
无论如何,一定要检查函数调用的返回值。几乎所有这些函数都可能失败,并且检测和处理这些函数要好于理解当你错误地认为每个调用都成功时可能形成的纠结。
答案 1 :(得分:0)
Fifos需要在开放时间进行一些同步。默认情况下,open(s)是阻塞的,因此一个open for read被阻塞,直到其他一些打开相同的fifo进行读取,而converse(这使得peer要同步进行通信)。您可以使用O_NONBLOCK
打开以进行阅读,而没有实际的开放对等,但反之亦然,因为在没有读取对等体的同时打开写入会导致错误(让进程尝试写入时没有读者被认为是无意义的。)
例如,您可以阅读Linux Fifo manual entry。