pilirono23
pilirono23

Reputation: 11

Simple fork() program

I am trying to make a program that checks a list of steam servers using fork. I saw that if i put 100.000 lines servers often the program goes in a wired loop and checks the same servers over and over and over again. After a debug i see that even a simple program that prints the server ip goes unexpected.

Program:

#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);
}

Output :

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

Expected output :

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

Do i forget something? Seems like the heap is corrupted. And why i see Beginning forking as if the program runs again from the begining? I know that forking is making another process but I though that fork() forks the program from the point where fork() is.

Thank you.

EDIT : solution is getline() is repeatedly reading the file, when fork() is used

Upvotes: 0

Views: 204

Answers (2)

Luis Colorado
Luis Colorado

Reputation: 12635

You have several problems here:

  • You don't check the result of fork(2). This is by far the most serious problem, as you are doing 100,000 forks. As your manual page will show, fork() returns 0 in the child process, and the child's pid in the parent, if fork() happens to execute correctly. But fork() in your case will soon give you an error, as you cannot probably start 100,000 simultaneous processes in your system. fork() returns -1 in case of error, and you don't check for it, so once it is unable to generate new processes, you'll end in the else part of your if command, considering what is an error as a successful command fork in the parent process. What this can lead is something bad, most probably.
  • As you have been told in another answer to your question, you'll receive a lot of repeated output (the buffer contents) if you try to call exit(3), instead of _exit(2), due to atexit() functionallyt making it to flush stdio buffers int both parent and child. On terminal output, this doesn't happen (you won't see this), as stdio uses line buffering on stdout to a terminal, so it flushes buffers before any chance to fork(). But only if the output device is a terminal, but not if it is a file (where buffers are flushed only whe buffer is full, or at exit time, then all non-flushed stdio buffers are flushed.) As I assume you are searching in some file, I assume you have redirected your output to a file, so a lot of repeated output is to be expected.
  • Also, instead of making a sleep(10) call at the end, to wait for child processes to finish, use a loop, wait(2)ing for child processes to terminate, until you get an error from wait. This will mean that you don't have more children alive.
  • And this is the most important thing. All system calls are documented in your online manual pages. Please, use them, as all of what I have explained is present there.
  • A minor issue. You are using old C library calls to do I/O (puts is an example) in C++. Try to avoid them. C++ was designed to be able to use all the C language calls, so many of the legacy software is reusable and works in C++. That's true for many legacy libraries, but stdio was superseeded a long time ago with a library (iostream) that is far better designed (due to the new object oriented capabilities in the new language, not trying to say that Stroustrup is better than Kernighan or Ritchie, my apologies beforehand) so, using C I/O in C++ is strongly deprecated.

You will see from all these comments, that your solution is not in the way you call getline(), as you have serious problems in your code.

Upvotes: 1

David Schwartz
David Schwartz

Reputation: 182743

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

        exit(0);
    }

This should be _exit(0);. Otherwise, you execute the exit handlers multiple times which has unpredictable effects on things like shared file descriptors.

Upvotes: 0

Related Questions