What's the process creation tree for this code (assuming all forks succeed)?
if(fork())
fork();
n = 3;
for(i=1;i<n;++i)
{
if(pid = fork())
break;
}
This is what I tried:
[0]
|
/\
[1] [1]
| |
[2] [2]
| |
[3] [3]
|
[4]
But that wasn't even one of the choices! Any help is appreciated.
First line:
if (fork())
After this fork, there are two processes, the parent and the child. In the parent, fork() returns nonzero. In the child, fork() returns zero. This means that the next line will run only in the parent.
fork();
The parent forks again. Now there are three processes, and all three will run the rest of the code.
for(i=1;i<n;++i)
{
if(pid = fork())
break;
}
First, i=1. Each of the three processes creates a child, sees a nonzero result, and breaks out of the loop. So the original three processes are done. But the children will keep going.
Next time through the loop, i=2. The same thing happens. Each of the three child process forks off a child of its own, sees a nonzero result, and breaks. The three new children will keep going.
And so on up to i=n-1.
I'll spare you my attempts at ASCII art, but the resulting tree looks a bit like a certain familiar piece of silverware...
Related
I am learning about sending signals. I came across SIGSTOP and SIGCONT to pause and then continue a running process respectively.
As far as I understand, when we execute a fork(), we do not know whether the parent or the child would execute first. It is dependent on the architecture of the process scheduler. This is why if for example after the fork we print something separately in the parent and child, the order of execution cannot be determined. (Unless we are using wait() in parent to synchronize the two processes).
Now, I am sending a SIGSTOP signal from parent to child and then after the parent has done some computation, sending a SIGCONT signal to child to resume operation. So far, every time I run the code, no code under the child process executes. But I am wondering if this will always be the case? Could there be a situation where an instruction in the child process gets executed before it receives the SIGSTOP from its parent? Here is some sample code:
pid_t pid_c = fork();
if (pid_c == 0){
printf("Hello I am the child process!\n");
}
else {
kill(pid_c, SIGSTOP);
printf("Hello I am the parent process!\n");
// do some computation
kill(pid_c, SIGCONT);
wait(&NULL)
}
When I try executing the above code, the parent process always starts with printing the statements so the SIGSTOP is able to pause the child execution before it can execute anything. Does this always happen with SIGSTOP or is this just architecture dependent? I mean could there be a case where the child prints "Hello I am the child process!" before getting paused?
Any suggestions are much appreciated! Thank you!
I am trying to send some signals (e.g. SIGSTOP, SIGUSR1) from the parent process based on different user inputs to the child process. The parent process keeps waiting for user input and sends the corresponding signals to the child. If there is no user input, the child does its own job.
I put my Ocaml code here but I am not sure I used the right way to do it.
I am writing in OCaml but solutions in other languages (e.g. C/Python) are also welcome.
let cr, pw = Unix.pipe () in
let pr, cw = Unix.pipe () in
match Unix.fork () with
| 0 -> (* child *)
Unix.close pr;
Unix.close pw;
Unix.dup2 cw Unix.stdout;
Unix.execvp ... (* execute something *)
| pid -> (* parent *)
Unix.close cr;
Unix.close cw;
Unix.dup2 pr Unix.stdin;
while true do
try
match Unix.select [pr] [] [] 0.1 with
| ([], [], []) -> (* no user input *)
(* I assume it should do next iteration and wait for next user input *)
raise Exit
| (_, _, _) -> (* some user input *)
let i = read_int () in
(* send signal to the child process *)
if i = 1 then Unix.kill pid Sys.sigstop
else if i = 2 then Unix.kill pid Sys.sigusr1;
with Exit -> ()
done
Meanwhile, if I would like to define some signals (using SIGUSR1), how and where should I do it?
Thanks!
It's not very clear what you're trying to do. Here are some comments on the code you show.
The parent process seems to be reading a pipe that it has itself created (pr). But you say the parent process is waiting for user input. User input isn't going to show up in a pipe that you create yourself.
Almost always you look for user input by reading the standard input, Unix.stdin.
The code creates another pipe that appears to be intended for the use of the child process, but there are no arrangements for the file descriptors of the pipe to be accessed by the child. The child will instead read the standard input of the parent and write to the parent's standard output.
Your code calls select with a timeout of 0.1 seconds. This means the call will return 10 times per second whether there is any input in the pipe or not. Every time it returns it will write a newline. So the output will be a stream of newlines appearing at the rate of around 10 per second.
You say you want to define signals, but it's not at all clear what this means. If you mean you want to define signal handlers for the child, this isn't possible in the code you show. Handlers of signals are not preserved across a call to Unix.execvp. If you think about it, this is the only way things could work, since the execvp call obliterates all the code in the parent process and replaces it with code from some other executable file.
It is not difficult to fork a child and then send it signals. But it's not clear what you're trying to do with the pipes and with the select. And it's not clear what you expect the signals to do in the child process. If you explain these, it would be easier to give a more detailed answer.
Update
In general, it's not a good idea to modify code that you've posted to StackOverflow (other than to fix typos), because the previous comments and answers no longer make sense with the new code. It's better to post updated code.
Your new code looks more like you're trying to read input from the child through a pipe. This is more sensible, but then it is not what I would call "user input."
You haven't specified where the child's input is supposed to come from, but I suspect you are planning to send input through the other pipe.
If so, this is a notoriously unreliable setup due to buffering between the child process and its pipes. If you haven't written the code for the child process yourself, there's no way to be sure it will read the proper sized data from the read pipe and flush its output to the write pipe at appropriate times. The usual result is that things immediately stall and make no progress.
If you are writing the code for the child process, you need to make sure it reads data in sizes that are being written by the parent. If the child asks for more data than this, it will block. If the parent is waiting for the answer to appear in its read pipe, you will have deadlock (which is the usual result unless you're very careful).
You also need to make sure the child flushes its output any time it is ready to be read by the parent process. And you also need to flush the output of the parent process any time you want it to be read by the child process. (And the parent has to write data in the sizes that are expected by the child.)
You haven't explained what you're trying to do with signals, so I can't help with that. It doesn't make much sense (to me) to read integer values written by the child process and send signals to the child process in response.
Here is some code that works. It doesn't do anything with signals, because I don't understand what you're trying to do. But it sets up the pipes properly and sends some fixed-length lines of text through the child process. The child process just changes all the characters to upper case.
let cr, pw = Unix.pipe ()
let pr, cw = Unix.pipe ()
let () =
match Unix.fork () with
| 0 -> (* Child process *)
Unix.close pr;
Unix.close pw;
Unix.dup2 cr Unix.stdin;
Unix.dup2 cw Unix.stdout;
Unix.close cr;
Unix.close cw;
let rec loop () =
match really_input_string stdin 6 with
| line ->
let ucline = String.uppercase_ascii line in
output_string stdout ucline;
flush stdout;
loop ()
| exception End_of_file -> exit 0
in
loop ()
| pid ->
(* Parent process *)
Unix.close cr;
Unix.close cw;
Unix.dup2 pr Unix.stdin;
Unix.close pr;
List.iter (fun s ->
let slen = String.length s in
ignore (Unix.write_substring pw s 0 slen);
let (rds, _, _) =
Unix.select [Unix.stdin] [] [] (-1.0)
in
if rds <> [] then
match really_input_string stdin 6 with
| line -> output_string stdout line
| exception End_of_file ->
print_endline "unexpected EOF"
)
["line1\n"; "again\n"];
Unix.close pw;
exit 0
When I run it I see this:
$ ocaml unix.cma m.cmo
LINE1
AGAIN
If you change either of the test lines to be shorter than 6 bytes, you'll see the deadlock that usually happens when people try to set up this dual-pipe scheme.
Your code for sending signals looks OK, but I don't know what you expect to happen when you send one.
I'm having trouble to understand how fork() works when it is used as a condition. I know that fork() creates a child process as an exact copy of the parent process. My question is, how many processes are created in the following program? Here is the code:
int global = 0;
int main() {
while(global < 5 && !fork()) {
sleep(1);
global += 1;
}
printf("%d\n", global);
return 0;
}
I was a assuming that for each fork() call, every process that is already running will create a child process and continue like that as long as the variable global reaches the value of 5.
The fork() call returns 0 in the child and the pid of the child in the parent.
Therefore, in the parent, the second condition will evaluate to 0, and the loop will exit and then print. In the child, the second condition will evaluate to non-zero, and the loop will fork again with a higher value of global (which is inherited).
Thus, we will see a total of 5 new processes in addition to the parent.
I think the output should be first child process should be executed the second child then parent but on compiling it gives the first line of first child and then first line of second child then again second line of first child and second line of second child. Here is the code in question:
#include<stdio.h>
int main() {
int pid,dip;
pid=fork();
if(pid==0) {
printf("1st child's process id is %d \n",getpid());
printf("first child dead");
} else {
dip=fork();
if(dip==0) {
printf("2nd child process id is %d\n",getpid());
printf("Second child dead");
} else {
printf("Child with pid %d died \n",wait(0));
printf("Child with pid %d died \n",wait(0));
printf("I am the parent");
}
}
return 0;
}
The order of execution there is indeterminate. There are three processes, the parent, and two children. So there are 3! = 6 possibilities in terms of what order they complete in.
If you run that code enough times, you'll see all 6 such possibilities, although there may be a tendency toward one or two in particular.
Since there are several printf()s -- one of which is not flushed with a newline -- in each process, there are more that just 6 possibilities WRT what order these lines appear in. Two lines from the same process will always be sequential (i.e., the first will appear before the second) but a line from another process could appear in between them.
How would I approach creating a process hierarchy that would look like a balanced ternary tree of depth N? ... meaning each process has 3 children so there would be (3^N-1)/2 processes in a tree of depth N. To create the new processes, I only want to use fork().
This is what I have so far but I don't think it works because I don't deal with process IDs and also I really don't think I should do this recursively:
void createTernaryTree(int n) {
if((n-1) == 0) return;
else {
int x;
for(x=0; x<3; x++) {
fork();
createTernaryTree(n-1);
}
}
}
Thanks,
Hristo
This bit does not look right to me:
for(x=0; x<3; x++) {
fork();
createTernaryTree(n-1);
}
The problem is that both the parent and the child continue looping and do the recursion.
Based on the return from fork (0 in the child, > 0 in the parent, -1 on error), you should decide whether to loop or recurse.
The code shown would do the job The code shown would nearly do the job (but there's a subtle problem). The other difficulty would be showing that it does the job.
The problem is that the code doesn't behave differently for the child and the parent processes after the fork. The parent process needs to complete its loop. Each child needs to restart a loop at the next level:
for (int x = 0; x < 3; x++) // C99
{
if (fork() == 0)
{
createTernaryTree(n-1);
break; // Per comment from R Samuel Klatchko
}
}
pause(); // See below
You could (should) add a 'pause();' call after the loop; this would send the parent process into suspended animation until it receives a signal. You could then show that you have a tree of processes. Alternatively, use 'sleep(30)' or some other way of suspending the processes. You don't want them to exit immediately; they'll do that too quickly for you to be able to demonstrate the tree structure.
In theory, you might want to track whether 'fork()' succeeds; in practice, it isn't clear what you'd do differently except, perhaps, not try to create the second child if the first fails (but that's likely to fail anyway, so blindly trying is probably best in the circumstances - but remember that in other situations, it would usually matter a lot).
Trees are inherently recursive structures; using recursion to manage them is often the neatest way to deal with them. This looks like it is tail recursion which means that it can be converted into a looping structure fairly easily. However, managing a data structure to keep tabs on what is happening is going to be harder than just doing it recursively.