Простая программа fork () - PullRequest
0 голосов
/ 06 апреля 2020

Я пытаюсь создать программу, которая проверяет список серверов Steam, используя fork. Я видел, что если я ставлю 100 000 серверов строк, программа часто идет по проводной линии l oop и проверяет одни и те же серверы снова и снова. После отладки я вижу, что даже простая программа, которая печатает IP-адрес сервера, работает неожиданно.

Программа:

#include <iostream>
#include <sys/wait.h>
#include <stdio.h>
#include <cstring>
#include <unistd.h>
#include <string>

#include <ctype.h>
#include <stdlib.h>
#include <fstream>

#include <sstream>
#include <algorithm>
#include <iterator>
#include <regex>
#include <vector>

int main(int argc, char **argv)
{
    puts("Beginning program");

    int max_forks = 500;
    int num_forks = 0;

    FILE *fpxxx = fopen("servers", "r");
    if(fpxxx == NULL) {
        perror("Unable to open file!");
        exit(0);
    }

    char chunk[128];

    while(fgets(chunk, sizeof(chunk), fpxxx) != NULL)
    {
        // puts(chunk); // same result if put the line here

        if(!(fork()))
        {
            // sleep(3);
            puts(chunk);

            exit(0);
        }
        else
        {
            num_forks++;

            if (num_forks >= max_forks)
            {
                wait(NULL);
                num_forks--;
            }
        }
    }

    fclose(fpxxx);
    sleep(10);
}

Вывод:

Beginning forking
94.xxx.xxx.209

Beginning forking
184.xxx.xxx.117

Beginning forking
108.xxx.xxx.86

Beginning forking
178.xxx.xxx.140

Beginning forking
113.xxx.xxx.132

Beginning forking
45.xxx.xxx.16

... (many lines, thus servers.txt has 100.000+ ips)

# after a while i see
Beginning forking
178.xxx.xxx.140
# again and again and again


# sometimes i even see
Beginning forking
37.247.104.933.17.199.143

Ожидаемый результат:

94.xxx.xxx.209
184.xxx.xxx.117
108.xxx.xxx.86
178.xxx.xxx.140
113.xxx.xxx.132
45.xxx.xxx.16

Я что-то забыл? Похоже, куча повреждена. И почему я вижу Beginning forking, как будто программа снова запускается с самого начала? Я знаю, что разветвление делает другой процесс, но я думаю, что fork() разветвляет программу с того места, где находится fork().

Спасибо.

РЕДАКТИРОВАТЬ : getline () постоянно читает файл, когда используется fork ()

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

У вас есть несколько проблем:

  • Вы не проверяете результат fork(2). Это, безусловно, самая серьезная проблема, так как вы делаете 100 000 вилок. Как показывает ваша страница справочника, fork() возвращает 0 в дочернем процессе, а pid ребенка в родительском, , если fork() выполнится правильно. Но fork() в вашем случае будет скоро выдаст ошибку, так как вы не можете запустить 100 000 одновременных процессов в вашей системе. fork() возвращает -1 в случае ошибки, и вы не проверяете ее, поэтому, когда она не сможет генерировать новые процессы, вы закончите в else части вашей команды if, учитывая, что ошибка в качестве успешного командного форка в родительском процессе. Это может привести к чему-то плохому, скорее всего.
  • Как вам сказали в другом ответе на ваш вопрос, вы получите многократный вывод (содержимое буфера), если попытаетесь вызвать exit(3) вместо _exit(2), из-за функционально atexit() превращения в грипп sh stdio буферизует как родитель, так и потомок На выходе терминала этого не происходит (вы этого не увидите), так как stdio использует буферизацию строки на stdout для терминала, поэтому он сбрасывает буферы перед любой возможностью fork(). Но только если устройство вывода является терминалом, но не если это файл (где буферы сбрасываются только тогда, когда буфер заполнен или во время выхода, тогда все не очищенные буферы stdio сбрасываются.) Как я полагаю, вы выполняется поиск в каком-либо файле, я предполагаю, что вы перенаправили вывод в файл, поэтому следует ожидать многократного вывода.
  • Кроме того, вместо выполнения sleep(10) вызова в конце, чтобы дождаться завершения дочерних процессов sh, используйте al oop, wait(2) ing для завершения дочерних процессов, пока не получите ошибка от wait. Это будет означать, что у вас больше детей не осталось в живых.
  • И это самое главное. Все системные вызовы документированы на ваших страницах руководства онлайн. Пожалуйста, используйте их, так как там есть все, что я объяснил.
  • Незначительная проблема. Вы используете старые C библиотечные вызовы для ввода / вывода (puts - пример) в C ++. Старайтесь избегать их. C ++ был спроектирован так, чтобы можно было использовать все языковые вызовы C, поэтому многие устаревшие программы можно использовать повторно и работать на C ++. Это верно для многих устаревших библиотек, но stdio давно заменили go с библиотекой (iostream), которая намного лучше спроектирована (из-за новых объектно-ориентированных возможностей в новом языке, не пытаясь сказать что Stroustrup лучше, чем Kernighan или Ritch ie, заранее извиняюсь), поэтому использование C I / O в C ++ настоятельно не рекомендуется.

Из всех этих комментариев вы увидите, что ваши решение не в том, как вы звоните getline(), так как у вас есть серьезные проблемы в вашем коде.

0 голосов
/ 06 апреля 2020
    if(!(fork()))
    {
        // sleep(3);
        puts(chunk);

        exit(0);
    }

Это должно быть _exit(0);. В противном случае вы выполняете обработчики выхода несколько раз, что приводит к непредсказуемым последствиям для таких вещей, как дескрипторы общих файлов.

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