这可能是一个相当复杂的问题。情况如下:
我正在尝试编写一个带有两个命令行参数的程序:要生成的孩子的数量,以及用空格分隔的单词的文件名。
该程序获取文件,解析单词,必须使用 fputs 将每个单独的单词以循环方式放入管道(如第一个单词进入第一个管道,第二个单词进入第二个管道等)并附加这些管道到正确的产生的孩子。
在解析器解析单词并填充管道之后,产生 # 个子子进程,每个子进程从解析器接收一个管道,其中包含单词。然后将管道映射到标准输入以与 sort() 进程一起使用,然后将 sort() 进程的 stdout 输出附加到第二组管道(再次 #children *2)。这些来自孩子的输出管道然后被带到程序的抑制器部分,然后必须从每个管道的顶部取出一个单词,必须使用 fgets,找到最小的,打印它,丢弃它,然后替换它丢弃该管道中的第二个单词,再次查找最小的单词,直到所有管道都为空。
我知道可能有一种更简单的方法,但我决定创建一个长度为#children 的 char* 数组,因此从每个管道中,当我拉出一个单词时,我可以将它放入数组中循环并比较。当找到最小的单词时,最小单词的索引处的内容在打印该单词后设置为 NULL,并且整个 WHILE 循环的下一次迭代确保用数组中的下一个单词填充该数组的索引。对应的管道。WHILE 应该一直运行,直到数组中的所有单元格都为 NULL(不再有来自任何管道的单词)。
到目前为止,我只让 WHILE 循环迭代了 3 次,并且发现单词数组得到了它的第一组单词,它找到了最小的单词,打印它,将它设置为 NULL,但是在第二次迭代期间 NULL 内容数组的 被一个不是新词的新词替换。它是另一个管道的副本。
我不认为解析单词并将其放入管道中存在问题。我已经对其进行了广泛的测试,并且在 sort() 过程之前它似乎还不错。在排序过程之后,我恐怕只能猜测出了什么问题。我花了很多时间试图解决它,但无济于事。
所以,现在一些代码。我将发布儿童产卵部分,然后是抑制器。由于这仍在进行中,因此有点混乱,并且有几个变量仅在调试中真正使用。我提前道歉!!
子项的产生(将管道映射到标准输入/标准输出并创建 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++;
}
无论如何,如果你已经读到这里,我真诚地感谢你。这个问题困扰了我至少一个星期,任何建议/评论都非常感谢!
编辑:
据我所知,解析器将其正确拆分,并且我已经看到单词正确到达子进程。另外我昨晚做了更多的测试,抑制器首先拉出的单词是正确的单词。例如,如果您的单词列表是
关于沙发胡须的相机是伏特加裁判价格收益率
然后,假设您有 3 个孩子,当它进入管道时,它将是:第一个是相机胡须裁判,第二个是大约是的价格,第三个是沙发伏特加和产量。
当这些被排序时,第一个输出管道应该包含相机裁判须,第二个是大约价格,第三个是沙发产量伏特加。然后抑制器拿出相机,左右,沙发,并比较它们。在那之前它似乎运行良好,通过测试我发现它确实从排序列表中提取了正确的第一个单词。最小的将是 about,然后抑制器在比较数组中将其设置为 null,但这就是问题发生的地方。
问题出现在第二次迭代中。从每个管道中提取一个单词并进行比较后,然后将一个单词设置为 NULL,以便下一次迭代它被正确管道中的一个新单词替换。无论出于何种原因,在这一步,当 about 被(应该是)price 取代时,它实际上被 couch(这是第三个管道中的单词)所取代。
似乎它是从错误的管道中提取的,但根据我的代码,我看不出这是怎么可能的。
编辑2!!
我已经大大缩小了范围。通过使用 bzero(buffer, PIPE_BUF) 清除缓冲区;在从管道读取其他内容之前(在抑制器部分中,在检测到数组内容是否为 NULL 之后),以及我的 FILE* sortOutput 声明方式的一些更改(一个全局变量,而不是通过循环每次迭代重新定义它) 它现在抓取新单词。但是,当管道用完单词时,它仍然出于某种原因将空索引内容与单词进行比较(这意味着空索引内容是最小的!)
我该如何防止呢?