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 if
s, 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."
– Carlos Diego
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 aproc_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.– Wtrmute
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).
– Carlos Diego
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 callinggetppid()
. So "kill" iskill(pid, SIGKILL)
and "commit suicide" is eitherkill(getpid(), SIGKILL)
orexit(EXIT_FAILURE)
. Remember to include<signal.h>
. In fact, let me update the answer with these two new phases.– Wtrmute
Very well explained Wtrmute, helped mto same, its code clean and objective and its easy to understand explanations. Obgdo
– Carlos Diego
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.
– Carlos Diego
I confess I did not; the error is that in
proc_filho1()
andproc_filho2()
i wroteif (num_segundos == 15 & ! fork())
, with only one&
. Since this is the bit-a-bit operator, it does not shortcut Evaluation like the&&
makes and thefork()
is called always. Correcting.– Wtrmute
@Wtrmute, I used your reply as an example of IPC signal sending in this reply on CPI
– Jefferson Quesado
@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
– Carlos Diego
@Carlosdiego:
system()
does not interpolate variables; has a question of Sopt talking about exactly this.– Wtrmute