来自子项的scanf扫描父母已经扫描的内容
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了来自子项的scanf扫描父母已经扫描的内容相关的知识,希望对你有一定的参考价值。
我的程序及其两个子进程都以有序的方式从stdin读取输入。我发现的问题是:
鉴于此输入:
32
51453a
140
父进程读取32,这意味着第一个子进程需要再读取2个数字。然后,父进程通过管道发送1个字节,以指示它需要读取两个数字的第一个进程。当子进程接收信号并开始读取这些数字时,孩子将读取52 51453a而不是51453a和140。
我一直在努力理解为什么会发生这种情况,如何解决它或更好,我怎么能避免它。
我在Mac OSX上运行
编辑:此问题仅在从文件重定向输入时发生(运行./polygon <in.txt)。直接从控制台运行时,它不会发生。还添加了更多代码以提供更好的图片。
void runWriterProcess(char *outFile, int writerFd[2]) {
close(writerFd[1]);
close(STDIN_FILENO);
dup(writerFd[0]);
close(writerFd[0]);
char *const params[] = {"./writer", outFile, NULL};
execv("./writer", params);
}
void reader32(int INSIG, int OUTPUT) {
long unsigned polygonParts[2];
char runSignal[2], polygonBuffer[17];
int64 nextPolygon;
while(read(INSIG, runSignal, 1) > 0) {
scanf("%lx", &polygonParts[0]);
scanf("%lx", &polygonParts[1]);
nextPolygon = polygonParts[1];
nextPolygon = nextPolygon << 32;
nextPolygon += polygonParts[0];
sprintf(polygonBuffer, "%16llx", nextPolygon);
write(OUTPUT, polygonBuffer, (int)strlen(polygonBuffer));
}
finishError("reader32 ");
exit(EXIT_SUCCESS);
}
void reader64(int INSIG, int OUTPUT) {
char runSignal[2], polygonBuffer[17];
int64 nextPolygon;
while(read(INSIG, runSignal, 1) > 0) {
scanf("%16llx", &nextPolygon);
sprintf(polygonBuffer, "%16llx", nextPolygon);
write(OUTPUT, polygonBuffer, 16);
}
finishError("reader64 ");
exit(EXIT_SUCCESS);
}
void runMainLoop(int reader32, int reader64, int readPipe) {
long unsigned dummy[2];
int64 bigDummy, nextPolygon;
char polygonBuffer[17];
int readerToRun;
for(;;) {
scanf("%d", &readerToRun);
if (readerToRun == 32) {
write(reader32, "1", 1);
} else {
write(reader64, "1", 1);
}
read(readPipe, polygonBuffer, 16);
sscanf(polygonBuffer, "%16llx", &nextPolygon);
if(runOnPolygon(nextPolygon)) break;
}
write(reader64, "0
", 2);
}
void createReaders(pid_t *reader32pid, pid_t *reader64pid) {
int fd32[2], fd64[2], fdBoth[2], readerToRun;
long unsigned polygonParts[2];
int64 nextPolygon, dummy;
char runSignal[2], polygonBuffer[17];
polygonBuffer[16] = ' ';
pipe(fd32);
pipe(fd64);
pipe(fdBoth);
if ((*reader32pid = fork()) == 0) {
close(fd32[1]);
close(fd64[0]);
close(fd64[1]);
close(fdBoth[0]);
reader32(fd32[0], fdBoth[1]);
}
if ((*reader64pid = fork()) == 0) {
close(fd32[0]);
close(fd32[1]);
close(fd64[1]);
close(fdBoth[0]);
reader64(fd64[0], fdBoth[1]);
}
close(fd32[0]);
close(fd64[0]);
close(fdBoth[1]);
runMainLoop(fd32[1], fd64[1], fdBoth[0]);
close(fd32[1]);
close(fd64[1]);
wait(NULL);
wait(NULL);
finishError("main_process ");
}
void finishError(char processName[13]) {
char output[50];
sprintf(output, "%s pid=%d is going to exit
", processName, getpid());
write(STDERR_FILENO, output, strlen(output) + 1);
}
int main(int argc, const char *argv[])
{
polygonList.head = NULL;
polygonList.tail = NULL;
pid_t writerPid, reader32pid, reader64pid;
int writerFd[2];
char outFile[11];
scanf("%s", outFile);
pipe(writerFd);
if (fork() == 0) {
runWriterProcess(outFile, writerFd);
} else {
close(STDOUT_FILENO);
dup(writerFd[1]);
close(writerFd[0]);
close(writerFd[1]);
createReaders(&reader32pid, &reader64pid);
}
freeList();
return 0;
}
答案
@Someprogrammerdude已经解释了为什么会这样。如果您确实无法避免从标准输入读取父级和子级(或多个子级),那么您可以通过setvbuf()
函数将其设置为无缓冲。如果你这样做,你应该先做这件事,然后再从stdin
读取任何内容:
int result = setvbuf(stdin, NULL, _IONBF, 0);
if (result != 0) {
// handle error
}
请注意,这会影响性能。
另一答案
它被称为缓冲。当您使用fork
时,子进程几乎是父进程的完整副本,包括输入缓冲区等内容。
最好的解决方案(IMO)是不读取孩子的标准输入。而是让父进程完成所有输入,然后将它通过管道发送给子进程。
以上是关于来自子项的scanf扫描父母已经扫描的内容的主要内容,如果未能解决你的问题,请参考以下文章
Sonarqube:使用自定义 gradle 任务扫描子项目而不是整个项目