Error creating child - Process scheduling using Fork

Asked

Viewed 512 times

2

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

The Father process creates a Filho1 process in 10 seconds and a Filho2 process in

20 seconds and then you’re running indefinitely. Well, I developed the code, it creates the father, creates the son 1, but in the creation of the second son, it does not meet the condition and does not create. Somebody give me a hand.

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

2 answers

3


The logic you are using is wrong; to facilitate, we will break the code into multiple functions using the informal description you 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)(), Sleep a second, print your ID, and test if you’ve reached the ten-second point, then test if you’ve reached the twenty-second point. In both ifs, as the operator && has the characteristic of shortcut Evaluation, the second operand (! fork()) is not executed until the first (num_segundos == 10/num_segundos == 20) be true. So he repeats.

When num_segundos reaches ten, the first operand returns true and then it rotates the fork(), raising the first child. In the case of the parent process, it will receive the pid of the child process (which is greater than zero), which denied returns 0 (i.e., false). So 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 the then is skipped.

After that, the father only sleeps for a second, increases the num_segundos, and reports its status eternally.

In the case of children 1 and 2, they are raised in the fork(), that returns zero to them. Denied, turns one, then they enter the respective then, calling the function proc_filho(). This function takes 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 on main(), and children in the proc_filho(), avoiding having to test whether it’s the parent or child running.

Children have their own accountant (the num_segundos place to proc_filho()), and report their own state normally. They have no access to the father’s count, although they could receive from the father the amount of seconds they were created to simulate the father’s count by a simple sum.

Note that in this case we call getpid() all iterations to achieve our own pid; we could call once, before the loop, and store the number in a local variable if you like. But how getpid() is a system call simple and quick, I don’t see much need.

EDIT: Two new phases: First, each child creates a grandson (called grandson 1 and grandson 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, Filho1 kills Father. - In the moment 55 seconds, Filho1 kills his son and commits suicide two seconds after this. - 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 becomes different. We could also store these differences in some kind of data structure, but it’s not worth it here. Let’s assume those instants refer to the father’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 the distinct functionalities into distinct functions makes it easier to extend the behavior of the program. In this last phase, for example, each process ran a proc different from each other, so no longer needed to pass the name of the child; on the other hand, I passed the "date of birth" to be able to count the timing of tragedy correctly.

Do it all from one sitting main() is it possible? Technically yes, but the logic would be so complicated that it is very unlikely that you will hit it first (or tenth). Separating into roles is much easier to reason over each piece separately (here, the behavior of each actor separately).

  • Wtrmute I managed to solve changing the conditions, he creates the second son, but his code is much more spicy than mine. Now continuing the problem. I need to create the grandson 1 of the son 1 and the grandson 2 of the son 2. - "After 15 seconds after their respective creations. The processes Filho1, Filho2, Neto1 and Neto2 are also running indefinitely."

  • 1

    Then in this case, the grandchild’s creation goes on proc_filho(), in the same way that the father raised the children. Then I would recommend the creation of a proc_neto() that does not generate other great-grandchildren to rotate the grandchildren (unless you will need to generate great-grandchildren), or something similar. Divide to conquer.

  • Show partner, it worked the creation of the grandchildren tbm. Continuing and finally the problem. In the instant 50 seconds, Filho1 kills Father. - At an instant of 55 seconds, Filho1 kills his son and commits suicide two seconds later . - At 60 seconds, Neto2 kills his father and commits suicide three seconds later, , ending the family saga. (end of novel).

  • 1

    Ok, in this case you will want to save the return values of fork() in the case of children to know the pid of the grandchildren (so Son 1 can kill his own son). The parent pid can be passed to the children as parameter or the child calling getppid(). So "kill" is kill(pid, SIGKILL) and "commit suicide" is either kill(getpid(), SIGKILL) or exit(EXIT_FAILURE). Remember to include <signal.h>. In fact, let me update the answer with these two new phases.

  • Very well explained Wtrmute, helped mto same, its code clean and objective and its easy to understand explanations. Obgdo

  • Wtrmute you tested your code there? I surrounded it and presented some bugs in relation to the function of the son was. I fixed and circled, but he entered an infinite loop that generates more and more children until he sees the memory to the point of locking the pc.

  • I confess I did not; the error is that in proc_filho1() and proc_filho2() i wrote if (num_segundos == 15 & ! fork()), with only one &. Since this is the bit-a-bit operator, it does not shortcut Evaluation like the && makes and the fork() is called always. Correcting.

  • @Wtrmute, I used your reply as an example of IPC signal sending in this reply on CPI

  • @Wtrmute to show the process tree at the beginning of the execution, at the moment when all processes are created and at the end of the program, using the command (pstree -s <pid>). Using the system("pstree -s pidPai"); however it returns Nonexistent username: pidPai

  • @Carlosdiego: system() does not interpolate variables; has a question of Sopt talking about exactly this.

Show 5 more comments

1

How about a generic function capable of solving 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;
        }
    }
}

Example 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 */

Exit:

$ ./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.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.