Trying to understand forks and semaphores - c

What I am trying to do in my code is have a parent process that forks two children processes. This is how I've done it:
pid = fork();
if(pid != 1)
pid1 = fork();
The next thing I'm trying to do is switch between the processes continuously (from child to other child to parent, in that order) using semaphores. ie the child process will say A, the other child will say B, the parent will say C, the child will say D, and so on.
My two questions are:
Say you call sem_wait(sem) in a semaphore and the process blocks as it should. You then move on and the other process ends up calling sem_post(sem). Will the code following the sem_wait be immediately executed after the sem_post? ie does the execution "jump back" to the code after the sem_wait even if it doesn't come "next" in the program?
if(stuff){
a;
sem_wait(sem);
b;
}
c;
sem_post(sem);
Will b be executed even though it's "before" the post in terms of coming before it textually?
How can I identify the processes so that I may give one of them permission to execute? I have to confirm that a process is either child 1 , child 2 or parent before I give it permission to execute the code, but how can I tell? I tried to check using if statements (if(pid) != 0, if(pid() == 0 and if(pid1 == 0) assuming that the parent would have a return value of 0 for the the first fork and the children would have zero's for their respective forks) but this did not work. I checked their PID's and PPID's and they were all over the place).
All help is appreciated, thank you

Related

How can the multi-core cpu run the program interleaved?

The output of the program are not obviously contents from the printf()s in teh code. Instead it looks like characters in irregular sequence. I know the reason is because the parent process and child process are running
at the same time, but in this program I only see pid=fork(), which I think means pid is only the id of child process.
So why can the parent process print?
How do the two processes run together?
// fork.c: create a new process
#include "kernel/types.h"
#include "user/user.h"
int
main()
{
int pid;
pid = fork();
printf("fork() returned %d\n", pid);
if(pid == 0){
printf("child\n");
} else {
printf("parent\n");
}
exit(0);
}
output:
ffoorrkk(()) rreettuurrnende d 0
1c9h
ilpda
rent
I focus my answer on showing how the observed output can result from the shown program. I think that it will already clear things up for you.
This is your output.
I edited it to use a good guess of what is parent (p) and child (c):
ffoorrkk(()) rreettuurrnende d 0\n
cpcpcpcpcpcpcpcpcpcpcpcpccpcpcppccc
1 c9h\n
pccpcpp
ilpda\n
ccpcpcc
rent
pppp
If you only use the chars with a "c" beneath, you get
fork() returned 0
child
If you only use the chars with a "p" beneath, you get
fork() returned 19
parent
Split that way, it should match what you know about how fork() works.
Comments already provided the actual answer to the three "?"-adorned questions in title and body of your question post.
Lundin:
It creates two processes and they are executed just as any other process, decided by the OS scheduler.
Yourself:
each time fork() is called it will return twice, the parent process will return the id of child process, and child process will return 0
Maybe for putting a more obvious point on it:
The parent process receives the child ID and also continues executing the program after the fork().
That is why the output occurs twice, similarily, interleaved, with differences in PID value and the selected if branch.
Relevant is also that in the given situation there is no line buffering. Otherwise there would be no character-by-character interleaving and everthing would be much more readable.

Tracing a program with multiple forks in if/else block

I'm trying to trace this program. I see that it outputs 4 times when I run it, but I don't understand why.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
if (fork() == 0)
fork();
else
{
fork();
fork();
printf("%d\n", getpid());
}
}
To my knowledge, the if/else forks my program, then if we're in the child, it forks again. If we're in the parent, it runs the code in the else block. I get confused when I try to trace after this point, though.
Once the else statement forks again, aren't we in another child?
When do the children stop being spawned?
After getting it explained for me, I understand it now.
The first fork will spawn a child (let's call it c1):
if (fork() == 0)
The return value of fork is 0 when you're in the child. So, c1 will execute the if statement block:
fork();
The child created here, c2 (as well as c1) will both die, as they aren't going to execute the else block.
Meanwhile, the parent process will execute the else block.
fork();
This creates another child of the original parent process (c3). c3 will execute the next fork in the else block.
fork();
Now, we'll have c4, too.
Meanwhile, the original parent process will still have a fork that hasn't run. This creates the final child process, c5.
At the end of the run, there will be 4 prints: The original parent process, c3, c4, and c5.
fork in if is executed. There are two processes now child C1 and parent. Parent gets a non-zero number. Child gets 0.
Parent enters else block as it got non-zero return from fork. Now again there are two processes child C2 and parent - after executing fork in else block.
Parents fork again with C3.
Child C2 forks again with C4.
Note that C1 also forked but it will not do anything other than ending the if block. (We don't care about this).
So 4, printf execution - one by Parent, C2, C3 and C4.
The key one line Golden rule is:-
Both parent and child process start their execution right after the system call fork()
And each process ends when the control reaches the end of the function here it is main(). (Answering your last question).

Fork three independent processes that interact through pipes, wait for them to finish, then print terminate messages

So my programming assignment is to:
create 3 independent processes
have them send data to each other through pipes
when final data is sent, each of the three process will print their PID.
My question is, how do I get the processes to hold off so that the other processes can finish their tasks before terminating?
Is there a signal I need to send if the child is waiting?
Right now, I've got something like...
p1 = fork();
// For the first process
if (p1 == 0) {
// For the second process
p2 = fork();
if (p2 == 0) {
// For the third process
p3 = fork();
if (p3 == 0) {
}
}
}
// This is the parent
else {
}
Well your first child is forking the second child which is forking the next child, etc.
Is this really what's required here? It's difficult to say...is the parent supposed to have 3 direct children, siblings?
Here you're forking off this sort of ancestry,a child aving a child...parent with a grandchild, etc. If this is how it's supposed to be then the parent must wait for the first child to return...the first child must wait for it's child to return, and so on.
As for them outputting their PID...I'd say it was a simple case of having each individual child process output its PID.
All these things can be read about in great detail in the man pages and probably whatever coursework or lectures you attended prior to being given your assignment.
Best of luck.

C: fork() child processes

According to the textbook I am reading, the code below creates N child processes that will exit with unique statuses.
/* Parent creates N children */
for (i = 0; i < N; i++)
if ((pid[i] = Fork()) == 0) /* Child */
exit(100+i);
Earlier in the textbook, it states that the following code will have 8 lines of output:
int main(){
Fork();
Fork();
Fork();
printf("hello\n");
exit(0);
}
This leads me to believe that there are 2^n child processes, where n is the number of times fork() is called. Is the reason the first code only produces N child processes (as opposed to 2^N) because the child exits every time, so by the time the subsequent fork() is called, it only operates on the parent process?
Every successful call to fork(), creates a new process.
In the first example, the children processes (the return value of fork() being 0) call exit();, which means they won't call the next fork().
In the second example, every children process continues forking.
When fork() is called it copies the parent data and starts executing from that point individually. So the execution of the parent or child is depend on the scheduling of process. Whichever process get cpu time will be executed whether it is child or parent. We have to take care that which code should run by which process(child or process).

What is the difference between fork()!=0 and !fork() in process creation

Currently, I am doing some exercises on operating system based on UNIX. I have used the fork() system call to create a child process and the code snippet is as follows :
if(!fork())
{
printf("I am parent process.\n");
}
else
printf("I am child process.\n");
And this program first executes the child process and then parent process.
But, when I replace if(!fork()) by if(fork()!=0) then the parent block and then child block executes.Here my question is - does the result should be the same in both cases or there is some reason behind this? Thanks in advance!!
There is no guaranteed order of execution.
However, if(!fork()) and if(fork()!=0) do give opposite results logically: if fork() returns zero, then !fork() is true whilst fork()!=0 is false.
Also, from the man page for fork():
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
So the correct check is
pid_t pid = fork();
if(pid == -1) {
// ERROR in PARENT
} else if(pid == 0) {
// CHILD process
} else {
// PARENT process, and the child has ID pid
}
EDIT: As Wyzard says, you should definitely make sure you make use of pid later as well. (Also, fixed the type to be pid_t instead of int.)
You shouldn't really use either of those, because when the child finishes, it'll remain as a zombie until the parent finishes too. You should either capture the child's pid in a variable and use it to retrieve the child's exit status:
pid_t child_pid = fork();
if (child_pid == -1)
{
// Fork failed, check errno
}
else if (child_pid)
{
// Do parent stuff...
int status;
waitpid(child_pid, &status, 0);
}
else
{
// Child stuff
}
or you should use the "double-fork trick" to dissociate the child from the parent, so that the child won't remain as a zombie waiting for the parent to retrieve its exit status.
Also, you can't rely on the child executing before the parent after a fork. You have two processes, running concurrently, with no guarantee about relative order of execution. They may take turns, or they may run simultaneously on different CPU cores.
The order in which the parent and child get to their respective printf() statements is undefined. It is likely that if you were to repeat your tests a large number of times, the results would be similar for both, in that for either version there would be times that the parent prints first and times the parent prints last.
!fork() and fork() == 0 both behave in the same way.
The condition itself cannot be the reason the execution sequence is any different.
The process is replicated, which means that child is now competing with parent for resources, including CPU. It is the OS scheduler that decides which process will get the CPU.
The sequence in which child and parent processes are being execute is determined by the scheduler. It determines when and for how long each process is being executed by the processor. So the sequence of the output may vary for one and the same program code. It is purely coincidental that the change in the source code led to the change of the output sequence.
By the way, your printf's should be just the other way round: if fork() returns 0, it's the child, not the parent process.
See code example at http://en.wikipedia.org/wiki/Fork_%28operating_system%29. The German version of this article (http://de.wikipedia.org/wiki/Fork_%28Unix%29) contains a sample output and a short discusion about operation sequence.

Resources