首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从子扫描中扫描任何家长已经扫描过的

从子扫描中扫描任何家长已经扫描过的
EN

Stack Overflow用户
提问于 2017-12-21 14:48:19
回答 2查看 76关注 0票数 0

我的程序及其两个子进程都以有序的方式从stdin读取输入。我发现的问题是:

鉴于这一投入:

代码语言:javascript
复制
32
51453a
140

父进程读取32,这意味着第一个子进程需要多读2个数字。然后,父进程通过管道发送一个字节,向第一个进程发送信号,它需要读取两个数字。当子进程接收到信号并开始读取这些数字时,而不是51453 a和140,子进程读取32 51453 a。

我一直在努力理解为什么会发生这种情况,我如何才能解决它,或者更好地解决它,如何避免它。

我在Mac上运行

编辑:只有在从文件重定向输入时才会发生此问题(运行./polygon < in.txt)。从控制台直接运行时,不会发生这种情况。还增加了更多的代码,以提供更好的图片。

代码语言:javascript
复制
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\0");
    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\0");
    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\n", 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] = '\0';
    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\0");
}

void finishError(char processName[13]) {
    char output[50];
    sprintf(output, "%s pid=%d is going to exit\n", 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;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-21 15:46:48

@一些编程者已经解释了为什么会发生这种情况。如果您确实无法避免从标准输入中读取父和子(或多个子),则可以通过setvbuf()函数将其设置为非缓冲。如果您这样做,您应该首先做它,然后才能从stdin读取任何东西。

代码语言:javascript
复制
int result = setvbuf(stdin, NULL, _IONBF, 0);
if (result != 0) {
    // handle error
}

请注意,这对性能有影响。

票数 2
EN

Stack Overflow用户

发布于 2017-12-21 14:53:03

这叫缓冲。当您使用fork时,子进程几乎是父进程的完整副本,包括输入缓冲区之类的内容。

最好的解决方案(IMO)是不要从孩子的标准输入中阅读。相反,让父进程执行所有输入,然后通过管道将其全部发送给子进程。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47927400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档