使用fork()时奇怪的输出

时间:2018-10-19 20:43:47

标签: c linux process

我正在尝试创建一个基于时间的池:您要么回答所有问题,要么时间就到。我本来的逻辑是让孩子算数,由父母问问题,但我没有实现。因此,我决定创建两个孩子,让父母安排他们的行为。

第一个孩子数时间,而第二个孩子问问题。看起来很有效,除了在程序结束时,其余的问题也被打印出来了,这有点奇怪。我的猜测是,scanf仍在等待我按下某些键,然后在控制台中充斥着垃圾。

现在,输入一些代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int askQuestions(char* array[], int size){
    char* answer;
    for(int i =0 ; i < size ; i ++){
        printf("%s\n",array[i]);
        scanf("%s",&answer);
    }
    return 0;
}

int count(int bound){
    int index = 0;
    printf("Counting started....\n");


    while(index < bound){
        sleep(1);
        index++;
        printf("%d seconds left \n", bound-index);
    }

    printf("Time's up!\n");
    return 0;
}

int main(){
    char* questions[] = {"Q1","Q2","Q3"};
    int size = sizeof(questions)/sizeof(questions[0]);
    int countingTime = 3;
    int status;
    pid_t id1,id2;

    id1 = fork();
    if(id1 < 0){
        printf("Fork failed");
    }else{

        if(id1 == 0){
            status = count(countingTime);
            exit(status);
        }else{
            id2 = fork();
            if(id2 == 0){
                status = askQuestions(questions,size);
                exit(status);
            }
        } 
         wait(0);  
    }



    return 0;

}

输出看起来像这样:

Counting started....
Q1
2 seconds left
1 seconds left
0 seconds left
Time's up!
[modan@HP15-ManjaroCinnamon Test]$ Q2
Q3

P.S。流程肯定会停止。 (通过顶部检查) 预先感谢。

4 个答案:

答案 0 :(得分:3)

scanf()有两个问题:

char* answer;
...
scanf("%s",&answer);
  1. &answer应该读为answer
  2. 首先您永远不会为answer分配内存。

这引起undefined behaviour,这意味着您的程序完全有权执行自己喜欢的事情。 :)

(感谢@EugeneSh.指出缺少的与号!)

答案 1 :(得分:2)

大概您想在时间结束后杀死另一个子进程(或者,如果回答了问题,则杀死计时器);

仅在wait-1中的ECHILD返回errno所有个孩子都在等待)之后,才退出。

答案 2 :(得分:2)

其他文章已经指出了代码中的问题。

我只是在展示一种使用select()的替代方式,您想要做什么。

您可以这样做:

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

#define TIMER_IN_SECS 3

int main(void) {
    char* questions[] = {"Q1","Q2","Q3"};
    char answer[50] = {0};
    fd_set rfds;
    struct timeval tv;
    int retval = 0;
    int read_bytes = 0;
    time_t start = 0;
    time_t curr = 0;
    time_t remain = 0;

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    tv.tv_usec = 0;

    start = time(NULL);
    printf("You have %d seconds of time and your time start now..\n", TIMER_IN_SECS);

    for (size_t i = 0; i < sizeof(questions)/sizeof(questions[0]); i++) {
        curr = time(NULL);
        if ((remain = (TIMER_IN_SECS - (curr - start))) <= 0) {
            printf("Timeout!!! %d seconds are over\n", TIMER_IN_SECS);
            break;
        }

        printf ("%s\n", questions[i]);

        /* Wait up to remaining seconds. */
        tv.tv_sec = remain;
        retval = select(1, &rfds, NULL, NULL, &tv);

        if (retval == -1) {
            perror("select()");
            return -1;
        } 

        if (retval) {
            read_bytes = read(0, answer, 49);
            if (read_bytes == -1) {
                perror("read()");
                return -1;
            }
            if(answer[read_bytes-1] == '\n') {
                --read_bytes;
                answer[read_bytes] = '\0';
            }
            /* In case if user just pressed enter key to skip the question */
            if(read_bytes == 0) {
                printf("No input..\n");
            } else {
                printf("Answer given by you : %s\n", answer);
            }
        } else {
            printf("Timeout!!! %d seconds are over\n", TIMER_IN_SECS);
            break;
        }
    }

    return 0;
}

输出:

# ./mytimer
You have 3 seconds of time and your time start now..
Q1
ss
Answer given by you : ss
Q2
ff
Answer given by you : ff
Q3
e
Answer given by you : e

# ./mytimer
You have 3 seconds of time and your time start now..
Q1
tt
Answer given by you : tt
Q2
d
Answer given by you : d
Q3
Timeout!!! 3 seconds are over

# ./mytimer
You have 3 seconds of time and your time start now..
Q1
d
Answer given by you : d
Timeout!!! 3 seconds are over

答案 3 :(得分:1)

问题是您只打一次wait()。因此,父进程仅等待一个孩子退出,而不是等待两个孩子退出,然后退出自身,另一个孩子继续运行。在您的情况下,执行倒计时的子项首先完成,因此在父进程退出后,显示问题的子项将继续运行。

同时,shell仅在等待父进程。退出时,shell将显示下一个提示。这就是为什么在提示后看到打印出来的问题的原因。

您应该循环调用wait()

while (wait(0) != -1) {
}

在没有可等待的子项时它将返回-1,然后循环将结束。

您还应该解决@NPE提到的指针问题,但这不是输出奇怪的直接原因。