Consider:
int main()
{
if (fork() == 0){
printf("a");
}
else{
printf("b");
waitpid(-1, NULL, 0);
}
printf("c");
exit(0);
}
(from Computer Systems, Bryant - O'Hallaron).
We are asked for all the possible output sequences.
I answered: acbc, abcc, bacc.
However, I am missing one output compared to the solution (bcac). I thought this output was not possible because the parent process waits for its child to return before printing c (waitpid). Is this not true? Why? And, in that case, what is the difference between the code above and the same without the waitpid line?
I don't see any way bcac is possible. At first I expected some trickery based on the stdio buffers being flushed in an unexpected order. But even then:
The child won't output c until after it has output a. Therefore the first c in bcac must have come from the parent.
The parent won't output c until after the waitpid completes. But that can't happen until after the child is finished, including the final stdio flush that happens during exit(). Therefore the first c is always from the child.
Proof by contradiction has been achieved... the output can't be bcac.
Well, there is one thing you could do to mess up the order. You could exec the program inside a process that already has a child which is about to exit. If the pre-existing child exits before the new child prints a, then the main process will detect that exit with waitpid, and go ahead and print its stuff and possibly exit before the child prints anything.
This is something to watch out for in setuid programs: don't assume that because your program only created one child process that it only has one child process. If you're in an advanced defensive-code learning context this answer makes sense. In a unix-newbie context it doesn't seem relevant, and it's probably better to just say bcac is impossible, even though it's technically not true.
It's tricky, but the call to waitpid can be interrupted (returns -1 and errno is EINTR). In this case the parent can output c before the child outputs anything and bcac is possible.
To prevent bcac from occurring, either a signal mask needs to be set, or, better, the waitpid return value is checked and if it was interrupted gets called again.
Related
When using fork(), is it possible to ensure that the child process executes before the parent without using wait() in the parent?
This is related to a homework problem in the Process API chapter of Operating Systems: Three Easy Pieces, a free online operating systems book.
The problem says:
Write another program using fork(). The child process should
print "hello"; the parent process should print "goodbye". You should
try to ensure that the child process always prints first; can you do
this without calling wait() in the parent?
Here's my solution using wait():
#include <stdio.h>
#include <stdlib.h> // exit
#include <sys/wait.h> // wait
#include <unistd.h> // fork
int main(void) {
int f = fork();
if (f < 0) { // fork failed
fprintf(stderr, "fork failed\n");
exit(1);
} else if (f == 0) { // child
printf("hello\n");
} else { // parent
wait(NULL);
printf("goodbye\n");
}
}
After thinking about it, I decided the answer to the last question was "no, you can't", but then a later question seems to imply that you can:
Now write a program that uses wait() to wait for the child process
to finish in the parent. What does wait() return? What happens if
you use wait() in the child?
Am I interpreting the second question wrong? If not, how do you do what the first question asks? How can I make the child print first without using wait() in the parent?
I hope this answer is not too late.
Minutes ago, I have emailed Remiz(this book's author), and got such a replay(extract some segments):
Without calling wait() is hard, and not really the main point.
What you did -- learning about signals on your own -- is a good sign,
showing you will seek out deeper knowledge. Good for you!
Later, you'll be able to use a shared memory segment, and
either condition variables or semaphores, to solve this problem.
Create a pipe in the parent. After fork, close the write half in the parent and the read half in the child.
Then, poll for readability. Since the child never writes to it, it will wait until the child (and all grandchildren, unless you take special care) no longer exists, at which time poll will give a "read with hangup" response. (Alternatively, you could actually communicate over the pipe).
You should read about O_CLOEXEC. As a general rule, that flag should always be set unless you have a good reason to clear it.
I can't see why second question would imply that answer is "yes" to the first.
Yes there is plenty of solutions to obtain what asked, but of course I suspect that all are not in the "spirit" of the problem/question where the focus in on fork/wait primitives. The point is always to remember that you can't assume anything after a fork regarding the way processes ran relatively to each other.
To ensure the child process print first you need a kind of synchronization in between both processes, and there is a lot of system primitives that have a semantic of "communication" between processes (for example locks, semaphores, signals, etc). I doubt one of these is to be used her, as they are generally introduced slightly later in such a course.
Any other attempt only that will only rely on time assumption (like using sleep or loops to "slow" down the parent, etc) can lead to failure, means that you will not be able to prove that it will always succeed. Even if testing would probably show you that it seems correct, most of the runs you would try will not have the bad characteristics that lead to failure. Remember that except in realtime OSes, scheduling is almost an approximation of fair concurrency.
NOTE:
As Jonathan Leffler commented, I also suppose that using other wait-like primitives is forbidden (aka wait4, waitpid, etc) -- "spirit" argument.
I'm not sure whether this is against the spirit of the question, but I think that calling the pause system call in the parent process branch will cause the scheduler to immediately run the child process (if it didn't already run).
void main(){
if(fork()==0)
printf("a");
else{
printf("b");
waitpid(-1,NULL,0);
}
printf("c");
exit(0);
}
Question: what is the output of the program?
a. acbc
b. bcac
c. abcc
d. bacc
e. A or C or D (Correct Answer)
So I am trying to figure out why C is one of corret answer.The following is my reasoning:
The child process go first then stop and pass control to the parent process, ('a' print out)
then parent process executes ("b" print out) because of waitpid(),
parent pass
control back to child so in child process (c print out) and the child is reaped.
Finally, back to the parent process "c" print out. So we have abcc.
Am I right?
Theoretically, your answer is correct, it could happen like this (so at the end (a), (c), (d) seem they could happen).
Practically, the only correct answer is (a).
The reason for that is that stdio uses internally buffers for caching the output and avoiding expensive system calls. Therefore, until your program outputs `\n' (newline) or exits, there is no output at all.
So the real scenario is going to be:
child push character 'a' into buffer, then 'c' into buffer.
parent simultaneously pushes character 'b' into buffer and waits for the child.
child exits and flushes buffer containing "ac" before that.
parent returns from waitpid() and pushes 'c' into buffer.
parent exits and flushes buffer containing "bc".
About the second part:
SIGKILL can kill any process (apart from some system processes). Child process is regular process like any other.
waitpid is to wait for child process until it exits. It has nothing to do with killing processes, it only waits (either due its own exit or due to being killed, no matter by which signal).
Your reasoning about how C could happen is correct. Timing (going down) would look something like this:
Parent Child
a
b
(waitpid)
c
c
I'm using system("./foo 1 2 3") within C to call an external application. I use it inside a for cycle and I want to wait for the foo execution to complete (each execution takes 20/30 seconds) before going into the next cycle iteration. This is a MUST.
The returned system() value only tells me if the process was successfully started or not. So how can I do this?
I looked into fork() and wait() already but didn't manage to do what I want.
Edit:Here's my fork and wait code:
for(i=0;i<64;i++){
if((pid=fork()==-1)){
perror("fork error");
return -1;
}
else if(pid==0){
status=system("./foo 1 2 3"); //THESE 1 2 3 PARAMETERS CHANGE WITHIN EACH ITERATION
}
else{ /* start of parent process */
printf("Parent process started.n");
if ((pid = wait(&status)) == -1)/* Wait for child process. */
printf("wait error");
else { /* Check status. */
if (WIFSIGNALED(status) != 0)
printf("Child process ended because of signal %d.n",
WTERMSIG(status));
else if (WIFEXITED(status) != 0)
printf("Child process ended normally; status = %d.n",
WEXITSTATUS(status));
else
printf("Child process did not end normally.n");
}
}
}
What happens when I do this is that the PC gets extremely slow to the point I need to manually reboot. So What I guess this is doing is starting 64 simultaneous child processes, causing the computer to become really slow.
On a POSIX system, the system function should already be waiting for the command to finish.
http://pubs.opengroup.org/onlinepubs/009695399/functions/system.html
If command is not a null pointer, system() shall return the termination status of the command language interpreter in the format specified by waitpid(). The termination status shall be as defined for the sh utility; otherwise, the termination status is unspecified. If some error prevents the command language interpreter from executing after the child process is created, the return value from system() shall be as if the command language interpreter had terminated using exit(127) or _exit(127). If a child process cannot be created, or if the termination status for the command language interpreter cannot be obtained, system() shall return -1 and set errno to indicate the error.
The one thing to watch out for is if you're starting the program in the background within the command (i.e. if you're doing "./foo &") - the obvious answer is just don't do that.
After you call fork, the child calls system which starts another child that foo runs in. Once it completes, the child continues the next iteration of the for loop. So after the first loop iteration you have 2 processes, then 4 after the next, and so forth. You're spawning off processes at an exponential rate which causes the system to grind to a halt.
There are a few ways to address this:
After the call to system, you have to call exit so the forked off child quits.
Use exec instead of system. This will start foo in the same process as the child. A successful call to exec does not return, however if it fails you still want to print an error and call exit after exec.
Don't bother with fork or wait at all and just call system in a loop, since system doesn't return until the command is completed.
EDIT:
This loop is exhibiting some strange behavior. Here is the culprit:
if((pid=fork()==-1)){
You've got some misplaces parenthesis here. The innermost expression is pid=fork()==-1. Because == has higher precedence than =, it first evaluates fork()==-1. If fork was successful, this evaluates to false, i.e. 0. So then it evaluates pid=0. So after this conditional, both the parent and the child have pid==0.
After applying one of the above changes, put the parenthesis in the right place:
if((pid=fork())==-1){
And everything should work fine.
wait(2)
All of these system calls are used to wait for state changes in a
child of the calling process, and obtain information about the child
whose state has changed. A state change is considered to be: the
child terminated; the child was stopped by a signal; or the child was
resumed by a signal. In the case of a terminated child, performing a
wait allows the system to release the resources associated with the
child; if a wait is not performed, then the terminated child remains
in a "zombie" state (see NOTES below).
If a child has already changed state, then these calls return
immediately. Otherwise, they block until either a child changes
state or a signal handler interrupts the call (assuming that system
calls are not automatically restarted using the SA_RESTART flag of
sigaction(2)). In the remainder of this page, a child whose state
has changed and which has not yet been waited upon by one of these
system calls is termed waitable.
I found out what the problem was.
I saw here: https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file
that in order to save the stderr to file I needed to do &>output.txt.
So I was doing "./foo 1 2 3 &>output.txt" but that & causes the system process to go into background.
+1 to #Random832 for guessing it (even though I never said I was using &> -sorry guys, my bad ).
Btw, if you want the stderr to be exported to a file you can use 2>output.txt
suppose if we have something like this:
printf("A");
fork();
printf("B");
Is the output going to be
1) ABAB
2) ABB
Can you please explain?
The right answer is that it depends on the buffering mode of stdout, which the other answers seem to be ignoring.
When you fork with unflushed buffers and then continue using stdio in both processes (instead of the usual quick execve or _exit in the child process), the stuff that was in the buffer at the time of the fork can be printed twice, once by each process.
It is undefined and ABB, ABAB and AABB is possible. First (ABB) can happen on unbuffered output only; with buffered output both processes will have the A in their output buffer. By calling fflush(3) before the fork(2) you can enforce this behavior.
Order of last chars depends on order of execution; most likely you will get ABAB as in this short example the program won't be interrupted by the scheduler.
The output should read as "ABB"
fork copies the entire program into a new memory space and continues from the fork. Since both processes are running the same code, I would save the process id that is returned from fork, so the rest of your program knows what to do.
the output is simply abb. Fork create one new child process so after execution of fork() two process will run and generally child process first get the chance to executes. See before fork only one process so the out put before fork only once A. Then fork executes and hence two different process now running each will print B and hence output is ABB.
To my previous question about segmentation fault ,I got very useful answers.Thanks for those who have responded.
#include<stdio.h>
main()
{
printf("hello");
int pid = fork();
wait(NULL);
}
output: hellohello.
In this the child process starts executing form the beginning.
If Iam not wrong , then how the program works if I put the sem_open before fork()
(ref answers to :prev questions)
I need a clear explanation about segmentation fault which happens occasionally and not always. And why not always... If there is any error in coding then it should occur always right...?
fork creates a clone of your process. Conceptually speaking, all state of the parent also ends up in the child. This includes:
CPU registers (including the instruction pointer, which defines where in the code your program is)
Memory (as an optimization your kernel will most likely mark all pages as copy-on-write, but semantically speaking it should be the same as copying all memory.)
File descriptors
Therefore... Your program will not "start running" from anywhere... All the state that you had when you called fork will propagate to the child. The child will return from fork just as the parent will.
As for what you can do after a fork... I'm not sure about what POSIX says, but I wouldn't rely on semaphores doing the right thing after a fork. You might need an inter-process semaphore (see man sem_open, or the pshared parameter of sem_init). In my experience cross-process semaphores aren't really well supported on free Unix type OS's... (Example: Some BSDs always fail with ENOSYS if you ever try to create one.)
#GregS mentions the duplicated "hello" strings after a fork. He is correct to say that stdio (i.e. FILE*) will buffer in user-space memory, and that a fork leads to the string being buffered in two processes. You might want to call fflush(stdout); fflush(stderr); and flush any other important FILE* handles before a fork.
No, it starts from the fork(), which returns 0 in the child or the child's process ID in the parent.
You see "hello" twice because the standard output is buffered, and has not actually been written at the point of the fork. Both parent and child then actually write the buffered output. If you fflush(stdout); after the printf(), you should see it only once.