Странный вывод при использовании fork () - PullRequest
0 голосов
/ 19 октября 2018

Я пытаюсь создать пул на основе времени: вы либо даете ответ на все вопросы, либо время истекло.Моя первоначальная логика заключалась в том, чтобы заставить ребенка считать, а родителя задавать вопросы, но я не смог это реализовать.Таким образом, я решил создать 2 детей и позволить родителям управлять их поведением.

Первый ребенок считает время, а второй задает вопросы.Кажется, это работает, за исключением конца программы, остальные вопросы также печатаются, что довольно странно.Я предполагаю, что 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

PS процессы определенно останавливаются.(проверил это сверху) Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 20 октября 2018

Другие посты уже указывали на проблемы в вашем коде.

Я просто показываю альтернативный способ делать то, что вы хотите сделать, используя 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
0 голосов
/ 20 октября 2018

Предположительно, вы захотите убить другой подпроцесс после истечения времени (или убить таймер, если на вопросы даны ответы);

И выход только после wait ed до возврата -1 с ECHILD в errno ( все ожидающих детей).

0 голосов
/ 20 октября 2018

Проблема в том, что вы звоните wait() только один раз.Таким образом, родительский процесс ожидает только одного дочернего элемента, а не обоих, а затем завершает работу, а другой дочерний процесс продолжает работать.В вашем случае дочерний элемент, который выполняет обратный отсчет, завершает работу первым, поэтому дочерний элемент, который печатает вопросы, продолжает работать после выхода из родительского процесса.

Между тем, оболочка ожидает только родительский процесс.Когда он выходит, оболочка печатает следующую подсказку.Вот почему вы видите вопросы, напечатанные после приглашения.

Вы должны позвонить wait() в цикле:

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

Он вернет -1, когда нет детей, ожидающих ожидания, затем цикл завершится.

Вам также нужно исправить проблему с указателем, о которой упоминал @NPE, но это не является прямой причиной странного вывода.

0 голосов
/ 19 октября 2018

Есть две проблемы с scanf():

char* answer;
...
scanf("%s",&answer);
  1. &answer должен читать answer.
  2. Вы никогда не выделяете память для answer впервое место.

Это приводит к неопределенному поведению , означающему, что ваша программа имеет полное право делать все, что пожелает.:)

(Спасибо @EugeneSh. за указание на отсутствующий амперсанд!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...