これはおそらくかなり複雑な問題になるでしょう。状況は次のとおりです。
私は 2 つのコマンド ライン引数を取るプログラムを作成しようとしています: スポーンする子の数と、スペースで区切られた単語を含むファイルの名前です。
このプログラムはファイルを取得し、単語を解析し、fputs を使用して、ラウンド ロビン スタイルで個々の単語をパイプに配置する必要があります (最初の単語が最初のパイプに入る、2 番目の単語が 2 番目のパイプに入るなど)。これらのパイプをアタッチします。正しいスポーンされた子に。
パーサーが単語を解析してパイプを埋めた後、 # of children 子プロセスが生成され、それぞれが単語を含む 1 つのパイプをパーサーから受け取ります。その後、パイプは stdin にマップされ、sort() プロセスで使用されます。次に、sort() プロセスの stdout 出力が 2 番目のパイプのセットにアタッチされます (#children *2 も再び)。子からのこれらの出力パイプは、プログラムのサプレッサー部分に取り込まれ、各パイプの先頭から 1 つの単語を削除する必要があります。そのパイプからの 2 番目の単語で単語を破棄し、すべてのパイプが空になるまで、どれが最小であるかをもう一度見つけます。
はるかに簡単な方法がある可能性が高いことはわかっていますが、長さが #children の char* 配列を作成することにしたので、各パイプから単語を取得すると、それを配列に入れてループして比較できます。最小のものが見つかると、最小の単語のインデックスの内容は、その単語が出力された後に NULL に設定され、WHILE ループ全体の次の反復で、配列のその 1 つのインデックスが次の単語で埋められるようにします。対応パイプ。WHILE は、配列内のすべてのセルが NULL になるまで実行されることになっています (どのパイプからも単語が来なくなります)。
これまでのところ、WHILE ループを 3 回反復しただけで、単語配列が単語の最初のセットを取得し、最小のものを見つけて出力し、NULL に設定することを発見しましたが、2 回目の反復中に NULL コンテンツの配列は、新しい単語ではない新しい単語に置き換えられます。別のパイプからの複製です。
単語を解析してパイプに入れることに問題があるとは思いません。私はそれを広範囲にテストしましたが、sort() プロセスまでは問題ないようです。並べ替えプロセスの後、何が問題なのかを推測することしかできないのではないかと心配しています。トラブルシューティングに何時間も費やしましたが、役に立ちませんでした。
だから、今いくつかのコード。子のスポーン セグメント、次にサプレッサーを投稿します。これはまだ進行中の作業であるため、少し面倒です。実際にはデバッグでのみ使用される変数がいくつかあります。先に失礼します!!
子のスポーン (パイプの stdin/stdout へのマッピングと sort() プロセスの作成):
//Collection of children need to be created specified by numChildren
int count;
for(count = 0; count < numChildren; count++){
printf("Count: %d\n", count);
switch((p = fork())){
case -1:
perror("Could not create child");
exit(-1);
case 0:
printf("Entering child\n");
close(0);
close(1);
dup(pipefds[count*2]);
dup(pipefds_two[(count*2)+1]);
execlp("/bin/sort", "sort", (char*)NULL); // (char*)NULL
break;
default:
//parent case -- p holds pid of child
printf("I am the parent, PID: %d\n", getpid());
child = wait(&status);
printf("pipefds_two: %d\n", pipefds_two[count*2]);
printf("Waited on child %d\n", child);
break;
}
}
最後に、サプレッサー:
//Suppressor - Reads one word from each pipe, compares, prints largest. Gets next word from that one pipe, compares, prints largest.
//Suppressor deletes duplicate words
//Reads from pipefds_two[count*2] position
char* words[numChildren];
int index, cont=1;
char* smallest;
int smallestIndex;
int checker;
int duplicateCount = 0;
int kindex;
char* temptwo;
int length;
int nullCount = 0;
int counter = 0;
for(kindex = 0; kindex < numChildren; kindex++){ //Initializes array with beginning values
FILE* sortOutput = fdopen(pipefds_two[kindex*2], "r");
fgets(buffer, PIPE_BUF, sortOutput);
words[kindex] = strdup(buffer);
fflush(sortOutput);
close(pipefds_two[(kindex*2)+1]);
}
while(counter < 3){ //This is where it prints out lowest values each "round", gets new words, and gets rid of duplicates
for(index = 0; index < numChildren; index++){
if(words[index] != NULL){ //Searches for first value in array that's not null to be "lowest" value
smallest = words[index];
smallestIndex = index;
break;
}
}
printf("Suppressor WHILE \n");
nullCount = 0;
printf("smallest word assigned: %s\n", smallest);
printf("smallest index %d\n", smallestIndex);
for(index = 0; index < numChildren; index++){ //need to loop through each pipe and pull a word, THEN compare them all!
printf("Suppressor FOR (index: %d word:%s)\n", index, words[index]);
if(words[index] == NULL){ //Fills in a NULL gap in the array with a new word from the corresponding pipe
FILE* sortOutput = fdopen(pipefds_two[index*2], "r");
fgets(buffer, PIPE_BUF, sortOutput);
words[index] = strdup(buffer);
fflush(sortOutput);
printf("the word which replaces a NULL: %s\n", words[index]);
}
}
for(index = 0; index < numChildren; index++){ //COMPARE ALL VALUES NOW THAT IT IS POPULATED
printf("compare FOR loop index: %d\n", index);
if((index != numChildren) && (words[index] != NULL) && (index != smallestIndex)){
printf("IF statement, (current arrayWord: %s)(smallest: %s)\n", words[index], smallest);
checker = strcmp(smallest, words[index]);
//printf("checker\n");
if(checker > 0){
smallest = words[index];
smallestIndex = index;
printf("New smallest assigned: %s\n New Smallest Index: %d\n", smallest, smallestIndex);
}else if(checker == 0){
printf("Same word\n");
words[index] = NULL;
duplicateCount++;
}else{
printf("ArrayWord is larger, smallest staying the same\n");
}
} if(index == numChildren-1){ //reached the end of the list
printf("The smallest this round is: %s\n", smallest);
words[smallestIndex] = NULL;
}
}
for(index = 0; index < numChildren; index++){ //Check for removed words!
printf("Checking if entries are null in array: index %d\n", index);
if(words[index] == NULL){
nullCount++;
printf("words at index null num: %d\n", nullCount);
}
}
//check to see if everything is null
counter++;
}
ともあれ、ここまで読んでいただき、誠にありがとうございました。この問題は少なくとも 1 週間は私を悩ませてきました。
編集:
私が知る限り、パーサーはそれを適切に分割し、単語が子プロセスに適切に到達するのを見てきました。さらに、昨夜もう少しテストを行いましたが、サプレッサーが最初に引き出す言葉は適切な言葉です. たとえば、単語リストが
カメラ について カウチ ひげ はい ウォッカ 審判 価格 利回り
次に、3人の子供がいると仮定してパイプに入ると、最初はカメラのひげの審判、2番目は約はいの価格、3番目はカウチウォッカと利回りになります.
これらを並べ替えると、最初の出力パイプにはカメラ審判のひげが含まれ、2 番目のパイプには about price yes が含まれ、3 番目のパイプにはカウチ イールド ウォッカが含まれます。次に、サプレッサーはカメラ、アバウト、カウチを引き出し、それらを比較します。その時点まではうまく機能しているようで、テストを通じて、実際にはソートされたリストから正しい最初の単語を引き出すことがわかりました. 最小のものは約であり、サプレッサーは比較配列で null に設定しますが、ここで問題が発生します。
問題は 2 回目の反復で発生します。各パイプから 1 つの単語が引き出されて比較が行われた後、その 1 つの単語が NULL に設定され、次の反復で正しいパイプからの新しい単語に置き換えられます。なんらかの理由で、このステップで、about が (本来あるべき) price に置き換えられているとき、実際には、couch (3 番目のパイプの単語) に置き換えられています。
間違ったパイプからプルしているようですが、私のコードに基づいて、それがどのように可能かわかりません。
編集2!!
かなり絞れました。bzero(buffer, PIPE_BUF); を使用してバッファをクリアする。パイプから追加の内容を読み取る前 (配列の内容が NULL であるかどうかを検出した後、サプレッサー部分内)、および FILE* sortOutput が宣言されている方法をいくつか変更します (ループの反復ごとに再定義するのではなく、1 つのグローバル変数) ) 新しい単語を取得するようになりました。しかし、パイプが単語を使い果たしたとき、何らかの理由で空のインデックスの内容を単語と比較します (つまり、空のインデックスの内容が最小です!)
どうすればそれを防ぐことができますか?