2017-05-06 72 views
0

我目前正在学习C语言的多线程,但有一点我不太明白,我们的命名管道excersize。
我们期望做一个文件搜索系统的实现,该文件搜索系统可以找到文件并用一个进程添加到缓冲区,第二个进程应该从第一个进程的线程获取文件名,在该文件中找到搜索查询并返回第一个位置通过管道加工。我做了几乎所有的事情,但我很困惑如何做两个进程之间的沟通。C fifo保持阻塞状态

这里是我的代码,做通信:
的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为打开模式。然后打印“错误打开管道没有这样的设备或地址”的错误,所以我知道,不知怎的,我无法打开里面仆从的recvPipe,但我不知道什么是错误

回答

1

您的代码存在的问题之一是对execlp()的使用的明显误解。一旦成功,这个函数不会返回,所以它后面的代码将永远不会被执行。通常先执行fork(),然后在子进程中执行execlp(),如果execlp()失败,肯定会使孩子终止。父进程可能还需要最终等待分叉子进程。

此外,每个进程在尝试打开FIFO的写入结束时都会通过O_CREAT标志,这很奇怪,而且可能不合需要。这应该是没有必要的,因为每个人都已经创建了与mkfifo()的FIFO。即使在mkfifo()失败或其他进程在可以打开之前将其删除的情况下,也不希望以O_CREAT打开,因为这会为您提供常规文件而不是FIFO。

修复execlp()问题后,您也会遇到竞争状况。父进程依赖于孩子创建一个FIFO,但不等待该进程这样做。如果父母在孩子完成其mkfifo()之前达到其打开的尝试,您将无法获得所需的行为。

我建议让父母创建这两个 FIFO,然后创建子进程。孩子和父母必须合作打开一个FIFO的两端,然后再打开另一端的两端。开放阅读将阻止直到另一个打开相同的FIFO用于书写。

或者您可以使用普通(匿名)管道(请参阅pipe())而不是FIFO。这些创建在两端都是开放的,并且它们更适合于通过继承相关的进程之间的通信。

无论如何,一定要检查函数调用的返回值。几乎所有这些函数都可能失败,并且检测并处理该前沿比清理当您错误地假设每次调用成功时可能形成的纠结要好得多。

+0

感谢您的详细解答,让我明白exec的问题部分。所以对于匿名管道部分,我可以通过exec参数传递一个管道。我不认为这是可能的,因为所有参数都转换为char * – BrokenFrog

0

的FIFO需要在打开时有些同步。默认情况下,open(s)是阻塞的,所以读取的开放会被阻塞,直到其他读者打开相同的fifo进行读取,并且相反(这使对等体进行同步以进行通信)。您可以使用O_NONBLOCK打开阅读,而没有实际的开放式对等体,但反过来是错误的,因为在没有阅读对等体的情况下打开以进行书写会导致错误(在没有阅读器的情况下允许进程尝试写入如无意义)。

例如,您可以阅读Linux Fifo manual entry

+0

我不这么认为,我正确理解你的答案,所以你建议我做'fdrecv = open(recvPipe,O_RDONLY | O_NONBLOCK);'minion.c? – BrokenFrog