2017-05-06 9 views
0

私は現在Cでマルチスレッドを研究していますが、私たちの名前付きパイプではわかりにくいものがあります。
ファイルを検索して1つのプロセスでバッファに追加するファイル検索システムを実装することが期待されています.2番目のプロセスは最初のスレッドからファイル名を取り、そのファイル内の検索クエリを見つけ出し、パイプを介して処理する。私はほとんどすべてをしましたが、私は2つのプロセス間の通信をどうやって行うのか混乱しています。 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; 
} 

私はこの方法を実行すると、スレッドは印刷物応答がない場合はブロックされますIオープンモードにO_NONBLOCKに変更してください。それから、「エラーが発生しました」というエラーが表示されるので、何とかrecipPipeをminion内で開くことができませんでしたが、何が間違っているのか分かりません。

答えて

1

コードには、execlp()の使用に関する誤解があります。成功すると、この関数はを返さないため、それに続くコードは決して実行されません。 1つは通常fork()です。次に、子プロセスでexeclp()を実行します。execlp()が失敗した場合、子プロセスを終了させることが確実です。親プロセスは、最終的に分岐した子を待つ必要があるかもしれません。

また、FIFOの書き込み終了を試みるときに、各プロセスがO_CREATフラグを渡すことは奇妙であり、おそらく好ましくありません。それぞれがmkfifo()のFIFOを作成したばかりなので、これは不要です。 mkfifo()が失敗したり、開かれる前に他のプロセスがそれを削除した場合でも、O_CREATで開こうとしないと、FIFOでなく普通のファイルが得られます。

execlp()問題を修正すると、競合状態になることもあります。親プロセスは、子プロセスに依存してFIFOの1つを作成しますが、そのプロセスがそのプロセスを待機することはありません。子がそのmkfifo()を完了する前に親がオープン試行に達すると、あなたは望みの動作を得られません。

子プロセスを作成する前に、親プロセスで FIFOの両方を作成することをお勧めします。子と親は、一方のFIFOの両端を開くことによって協力して、他方のFIFOの両端をオープンする必要があります。読み取り用に開かれているものは、もう一方が書き込み用に同じFIFOを開くまでブロックされます。

または、FIFOの代わりに通常の(匿名の)パイプ(pipe()を参照)を使用できます。これらは両端でオープンに作成され、継承に関連するプロセス間の通信にはより自然です。

いずれにしても、の関数呼び出しの戻り値を確認してください。これらの関数のほとんどすべてが失敗する可能性があります。間違っていると仮定したときに発生する可能性のあるもつれを整理するよりも、すべての呼び出しが成功したことを検出して処理するほうがはるかに優れています。

+0

詳細な回答をいただきありがとうございます。私はexecの問題のある部分を理解できました。したがって、匿名のパイプ部分では、exec引数でパイプを渡すことはできますか?私はすべての引数がchar *にキャストされているので、それが可能であるとは思わなかった* – BrokenFrog

0

Fifosはオープン時に同期が必要です。デフォルトでは、open(s)はブロックされているので、readのためのopenは、同じfifoが読み込みになるまでブロックされ、逆にread(s)がブロックされます。 O_NONBLOCKを使用すると、実際のオープンピアは存在しませんが、読者がいない間に書き込みを開始するとエラーにつながるため、逆の場合はfalseになります(リーダーがない状態で書き込みを試みるプロセスに考慮されるため非センスとして)。

たとえば、Linux Fifo manual entryを読むことができます。

+0

あなたの答えを正しく理解しているとは思わないので、 'fdrecv = open(recvPipe、O_RDONLY | O_NONBLOCK);'をminion.cにすることをお勧めしますか? – BrokenFrog

関連する問題