C-программа итерирует слишком много при использовании fork внутри - PullRequest
1 голос
/ 18 апреля 2019

Я читаю строки текста из файла, и для каждой строки я обрабатываю его, используя несколько {fork () -> дочерних процессов, вызывающих execvp (), а родительский - wait ()}. в конце процесса я записываю результаты в файл.

Проблема в том, что цикл while, кажется, слишком много повторяется, а также запись в файл.

Файл results.csv содержит 6 строк, а не только 2 (итерация while выполняет итерацию текстового файла с двумя строками, но при использовании printf последняя строка читается дважды).

Что мне здесь не хватает?

Пример кода:

FILE* results = fopen("results.csv", "w");
if (results == NULL){
    fclose(fp);
    perror("Failed opening results file");
    exit(-1);
}
fdIn = open(inputPath, O_RDONLY);
if (fdIn < 0){
    perror("Failed opening input file");
    exit(-1);
}
while (fgets(student, sizeof(student), fp) != NULL) {
    // override end line char of unix ('\n') with '\0'
    student[strlen(student)-1] ='\0';
    pid = fork();
    if (pid < 0){
        close(fdIn);
        perror("Failed creating process for executing student's program");
        exit(-1);
    }
    if (pid == 0) {// son process code
        fdOut = open("tempOutput.txt", (O_WRONLY | O_CREAT | O_TRUNC), 0666);
        if (fdOut < 0){
            perror("Failed opening temporary output file");
            exit(-1);
        }
        close(1);
        dup(fdOut);
        close(fdOut);
        close(0);
        dup(fdIn);
        close(fdIn);
        char studProgPath[bufSize];
        strcpy(studProgPath,studentsFolderPath);
        strcat(studProgPath,"/");
        strcat(studProgPath,student);
        strcat(studProgPath,"/");
        strcat(studProgPath,"a.out");
        char * args[] = {"a.out", NULL};
        ret_code = execvp(studProgPath,args);
        if (ret_code == -1){
            perror("Failed executing student program");
            exit(-1);
        }
    }
    waited = wait(&stat);
    if (stat == -1){ // need to grade 0
        printf("%s,0\n",student);
    }else{ // open process to compare the output with the expected
        pid = fork();
        if (pid < 0){
            perror("Failed opening process for comparing outputs");
            exit(-1);
        }
        if(pid == 0) { // son process
            char * args[] = {"comp.exe",outputPath,"tempOutput.txt",NULL};
            ret_code = execvp("comp.exe",args);
            exit(ret_code);
        }
        waited = wait(&stat);
        if (stat == -1) {
            perror("Failed executing comparing program");
            exit(-1);
        } else if (stat == 0 || stat == 1) { // if outputs are not the same
            fprintf(results,"%s,0\n",student);
        } else { // matching outputs grade 100
            fprintf(results,"%s,100, pid: %d\n",student,getpid());
        }
    }
}

1 Ответ

1 голос
/ 19 апреля 2019

Файл, который получает тройные записи, открывается здесь:

FILE* results = fopen("results.csv", "w");

Следующие строки записывают в этот файл results, перед тем, как функция вызовет fork():

} else if (stat == 0 || stat == 1) { // if outputs are not the same
  fprintf(results,"%s,0\n",student); 
} else { // matching outputs grade 100 
  fprintf(results,"%s,100, pid: %d\n",student,getpid()); 
}

Этот файл должен быть сброшен с fflush(results) перед разветвлением, в противном случае буфер results может быть очищен три раза: в родительском и в двух копиях в дочерних.

Также, results и student должны быть закрыты с fclose(results) и student перед вызовом execvp. Если файлы не закрыты, то a.out может манипулировать файлом results. Я предполагаю, что a.out - это внешний код, который вы не контролируете.

while (fgets(student, sizeof(student), fp) != NULL) {
    // override end line char of unix ('\n') with '\0'
    student[strlen(student)-1] ='\0';
    fflush(results); // otherwise each child may flush the same chars
    pid = fork();
    if (pid < 0){
        fclose(results); // otherwise ./a.out might write to this file
        fclose(fp); // better also close it.
        close(fdIn);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...