Error creating child - Scheduling processes using fork

2

Write a C / C ++ program called novela.cpp that does the following:

The Parent process creates a Son1 process in 10 seconds and a Son2 process in

20 seconds and then runs indefinitely. Well, I developed the code, he creates the father, he creates the son 1, but in the creation of the second son, he does not attend to the condition and does not create. Someone gives me some help.

#include <stdio.h>
#include <unistd.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
//printf("--beginning of program\n");
int segundosPai=0;
int segundosFilho1=0;
int segundosFilho2=0;
int segundosNeto1=0;
int segundosNeto2 = 0;
bool pai, filho1, filho2, neto1, neto2;
pid_t pid = fork();
int pidPai, pidFilho1, pidFilho2, pidNeto1, pidNeto2;

while(true){
    segundosPai++;
    if (pid == 0)
    {   
        if(segundosPai >= 10){
            pidFilho1 = getpid();// processo filho 1
            filho1 = true;
            while(filho1 == true){
                segundosFilho1++;
                cout<<"Sou o FILHO 1, tenho "<<segundosFilho1<<" anos e o PID: "<<pidFilho1<<" e o PID do meu pai e: "<<getppid()<<"\n";
                sleep(1);
                //criacao do filho 2
                if(segundosPai >= 20){//ELE NAO ATENDE ESSA CONDIÇÃO
                    pidFilho2 = getpid();//processo filho 2
                    filho2 == true;
                    while(filho2 == true){
                        segundosFilho2++;
                        cout<<"Sou o FILHO 2, tenho "<<segundosFilho2<<" anos e o PID: "<<pidFilho2<<" e o PID do meu pai e: "<<getppid()<<"\n";
                        sleep(1);
                    }//fim while filho 2
                }
            }//fim while filho 1

        }           
    }
    else if (pid > 0)
    {   
        pidPai = getpid();
        pai = true;
        // processo pai
        cout<<"Sou o PAI, tenho "<<segundosPai<<" anos e o PID: "<<pidFilho1<<"\n";

    }
    else
    {
        // fork failed
        printf("Falha ao criar o fork!\n");
        return 1;
    }
    sleep(1);
}//fim do laço while

printf("--Fim do programa--\n");

return 0;
}
    
asked by anonymous 22.06.2017 / 01:51

2 answers

3

The logic you are using is wrong; to make it easier, let's break the code into multiple functions using the informal description you've made:

#include <iostream>
#include <unistd.h>

void
proc_filho(const char * nome) {
    int num_segundos = 0;
    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo " << nome << " (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
    }
}

int
main(int argc, char ** argv) {
    int num_segundos = 0;

    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo pai (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        // aos 10 segundos, gera o filho 1.
        if (num_segundos == 10 && ! fork()) proc_filho("filho 1");
        // aos 20 segundos, gera o filho 2.
        if (num_segundos == 20 && ! fork()) proc_filho("filho 2");
    }

    return 0;
}

The parent process is born in main)() , sleeps a second, prints its ID, and tests if it has reached the point of ten seconds, then tests if it has reached the point of twenty seconds. In both if s, since the && operator has the shortcut evaluation feature, the second operand ( ! fork() ) is not executed until the first ( num_segundos == 10 / num_segundos == 20 ) be true. So he goes on repeating.

When num_segundos reaches ten, the first operand returns true and then it runs fork() , creating the first child. In the case of the parent process, it will get the pid of the child process (which is greater than zero), which denied returns 0 (ie false). Then it does not enter the then . Ten seconds later, num_segundos reaches twenty, the first operand of the second if returns true, and the second fork() is evaluated. Again, a value greater than zero is returned, which denied becomes zero, then then is skipped.

After that, the parent only sleeps for a second, increments num_segundos , and reports its state forever.

In the case of children 1 and 2, they are created in fork() , which returns zero for them. Denied, turn one, then they enter their then , which invoke the proc_filho() function. This function receives the name of the process (for the purpose of reporting the state), and does not return. Thus, we guarantee that the parent will always run in main() , and children in proc_filho() , avoiding having to test whether the parent or child is running.

Children have their own counter (% local% to num_segundos ), and report their own status normally. They do not have access to the father's count, although they could receive from the father the number of seconds they were created to simulate the parent's count by a simple sum.

Note that in this case we call proc_filho() all iterations to get our own pid; we could call once before the loop , and save the number to a local variable, if you feel better. But since getpid() is a quick and simple system call , I do not see much need.

EDIT: Two new phases: First, each child creates a grandchild (called grandchild 1 and grandchild 2) after 15 seconds.

#include <iostream>
#include <unistd.h>

void
proc_neto(const char * nome) {
    int num_segundos = 0;
    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo " << nome << " (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
    }
}

void
proc_filho(const char * nome) {
    int num_segundos = 0;
    char nome_filho[7] = "neto x";

    // o dígito fica na 8ª posição do nome do filho, repete na 6ª do neto
    nome_filho[5] = nome[7];
    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo " << nome << " (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        if (num_segundos == 15 && ! fork()) proc_neto(nome_filho);
    }
}

int
main(int argc, char ** argv) {
    int num_segundos = 0;

    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo pai (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        // aos 10 segundos, gera o filho 1.
        if (num_segundos == 10 && ! fork()) proc_filho("filho 1");
        // aos 20 segundos, gera o filho 2.
        if (num_segundos == 20 && ! fork()) proc_filho("filho 2");
    }

    return 0;
}

Third and last phase: In the instant 50 seconds, Son1 kills Father. - In 55 seconds, Son1 kills his son and commits suicide two seconds after that. - In 60 seconds, Neto2 kills his father and commits suicide three seconds later, ending the family saga.

Here it is better to separate the procs of the two children and the two grandchildren, since their behavior begins to differ. We could also save these differences in some kind of data structure, but it's not worth it here. Let's assume that these instants refer to the parent's clock:

#include <iostream>
#include <unistd.h>
#include <signal.h>

void
proc_neto1(int dtnasc) {
    int num_segundos = 0;
    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo neto 1 (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
    }
}

void
proc_neto2(int dtnasc) {
    int num_segundos = 0;
    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo neto 2 (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        if (dtnasc + num_segundos == 60) {
            cout << "Neto 2 ficou louco! Matou seu pai (PID " << getppid() << ")" << endl;
            kill(getppid(), SIGKILL);
        }
        if (dtnasc + num_segundos == 63) {
            cout << "Não aguentando a pressão, neto 2 se suicida." << endl;
            kill(getppid(), SIGKILL);
        }
    }
}

void
proc_filho1(int dtnasc) {
    int num_segundos = 0;
    int pid_filho = 0;

    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo filho 1 (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        if (num_segundos == 15 && ! (pid_filho = fork())) proc_neto1(dtnasc + num_segundos);
        if (dtnasc + num_segundos == 50) {
            cout << "Filho 1 ficou louco! Matou seu pai (PID = " << getppid() << ")" << endl;
            kill(getppid(), SIGKILL);
        }
        if (dtnasc + num_segundos == 55) {
            cout << "Filho 1 continua louco! Matou seu filho (PID " << pid_filho << ")" << endl;
            kill(pid_filho, SIGKILL);
        }
        if (dtnasc + num_segundos == 57) {
            cout << "Não aguentando a pressão, filho 1 se suicida." << endl;
            kill(getpid(), SIGKILL);
        }
    }
}

void
proc_filho2(const char * nome) {
    int num_segundos = 0;

    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo " << nome << " (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        if (num_segundos == 15 && ! fork()) proc_neto2(dtnasc + num_segundos);
    }
}

int
main(int argc, char ** argv) {
    int num_segundos = 0;

    while (true) {
        sleep(1);
        num_segundos ++;
        cout << "Sou o processo pai (PID " << getpid() << "), estou rodando há " << num_segundos << " segundos." << endl;
        // aos 10 segundos, gera o filho 1.
        if (num_segundos == 10 && ! fork()) proc_filho1(num_segundos);
        // aos 20 segundos, gera o filho 2.
        if (num_segundos == 20 && ! fork()) proc_filho2(num_segundos);
    }

    return 0;
}

As you can see, separating distinct features into distinct functions makes it easier to extend program behavior. In this last phase, for example, each process was running a proc different from the other, so it did not have to pass the name of the child anymore; on the other hand, I started to pass the "birth date" to be able to count the timing of the tragedy correctly.

Do this all from one sitting only in getpid() is it possible? Technically yes, but the logic would be so complicated that it is very unlikely that you will get it right first (or tenth). Separating into functions makes it much easier to reason about each piece separately (here, the behavior of each actor separately).

    
22.06.2017 / 18:27
1

What about a generic function that can solve the problem:

void fork_children( int count, int delay )
{
    int i = 0;
    int j = 0;
    pid_t pid = 0;

    for ( i = 0; i < count; i++)
    {
        sleep(delay);

        pid = fork();

        if( pid == 0 )
        {
            debug( "Processo filho iniciado.");

            for( j = 0; j < 20; j++ )
            {
                debug( "Processo filho trabalhando..." );
                sleep(1);
            }

            break;
        }
        else if( pid == -1 )
        {
            std::cerr << "Erro no fork()!" << std::endl;
            break;
        }
    }
}

Sample program (tested):

#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <iostream>

#include <unistd.h>


#define CHILDREN_COUNT (2)
#define FORK_DELAY     (10)


void debug( const char * msg )
{
    char timestamp[32] = {0};
    time_t timer;
    struct tm* info;

    time(&timer);
    info = localtime(&timer);

    strftime( timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", info );

    std::cout << "[" << timestamp << "]-[PID " << getpid() << "]: " << msg << std::endl;
}


void fork_children( int count, int delay )
{
    int i = 0;
    int j = 0;
    pid_t pid = 0;

    for ( i = 0; i < count; i++)
    {
        sleep(delay);

        pid = fork();

        if( pid == 0 )
        {
            debug( "Processo filho iniciado.");

            for( j = 0; j < 20; j++ )
            {
                debug( "Processo filho trabalhando..." );
                sleep(1);
            }

            break;
        }
        else if( pid == -1 )
        {
            std::cerr << "Erro no fork()!" << std::endl;
            break;
        }
    }
}


int main( int argc, char ** argv )
{
    debug( "Processo pai iniciado.");

    fork_children( CHILDREN_COUNT, FORK_DELAY );

    debug("Processo finalizado.");

    return 0;
}

/* fim-de-arquivo */

Output:

$ ./novela
[2017-06-22 15:42:51]-[PID 25321]: Processo pai iniciado.
[2017-06-22 15:43:01]-[PID 25323]: Processo filho iniciado.
[2017-06-22 15:43:01]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:02]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:03]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:04]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:05]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:06]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:07]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:08]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:09]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:10]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:11]-[PID 25321]: Processo finalizado.
[2017-06-22 15:43:11]-[PID 25324]: Processo filho iniciado.
[2017-06-22 15:43:11]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:11]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:12]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:12]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:13]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:13]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:14]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:14]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:15]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:15]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:16]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:16]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:17]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:17]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:18]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:18]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:19]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:19]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:20]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:20]-[PID 25323]: Processo filho trabalhando...
[2017-06-22 15:43:21]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:21]-[PID 25323]: Processo finalizado.
[2017-06-22 15:43:22]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:23]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:24]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:25]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:26]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:27]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:28]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:29]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:30]-[PID 25324]: Processo filho trabalhando...
[2017-06-22 15:43:31]-[PID 25324]: Processo finalizado.
    
22.06.2017 / 20:45