Fork and printf() - fork

So my output for the code below includes printing D twice, and I can't seem to understand why. It'll be great if someone could explain it to me.
int main() {
int r = fork();
printf("B\n");
int t = fork();
printf("C\n");
if(r == 0) {
printf("D\n");
} else if (r > 0 && t == 0){
printf("E\n");
}
printf("F\n");
return 0;
}
Thanks.

Let's use naming convention to easily describe how the code runs. Let's call the parent that executes X=fork() Xparent and the forked child Xchild. Parents end up with X > 0 and child with X==0.
You have a parent that executes r=fork() and t=fork() making it an Rparent and a Tparent.
We now know that Rchild will have r==0 and Tchild will have t==0.
However, the older child, Rchild, executes t=fork() making it a Tparent and forking a Tchild.
The Tchild forked by Rchild will have r==0, memories from parent and child are cloned.
Hence you end up with Rchild having r==0 and its child having r==0. Two processes printing D.

Related

Fork/ execlp in #pragma omp parallel for stops arbitrarily

I am programming a Kalman-Filter based realtime program in C using a large number of realizations. To generate the realization output I have to execute an external program (groundwater simulation software) about 100 times. I am therefore using OpenMP with fork and exceclp for parallelization of this block:
#pragma omp parallel for private(temp)
for(i=1;i<=n_real;i++){
/* Start ensemble model run */
int = fork();
int ffork = 0;
int status;
if (pid == 0) {
//Child process
log_info("Start Dadia for Ens %d on thread %d",i,omp_get_thread_num());
sprintf(temp,"ens_%d",i);
chdir(temp);
execlp("../SPRING/dadia","dadia","-return","-replace_kenn","73","ini.csv","CSV",NULL);
log_info("Could not execute function dadia - exit anyway");
ffork = 1;
_exit(1);
}
else{
//Parent process
wait(NULL);
if (ffork == 0){
log_info("DADIA run ens_%d successfully finished",i);
}
}
}
In general the code runs smoothly for small number of realizations (with 6 threads). However sometimes the code hangs in the last cycle of parallel iterations. The occurrence only happens if number iterations >> number threads. I tried scheduling the for loop with different options, but it didn't solve the problem. I know that fork is not the best solution to use with OpenMP. But I am wondring why it's sometimes hangs at arbitrary points.
Thank's a lot for any kind if feedback.
Different Ubuntu versions tried (including difffrent comiler versions)
This version finally seems to run stable. Thank's for your hints:
#pragma omp parallel for private(temp) schedule(dynamic)
for(i=1;i<=n_real;i++) {
/* Start ensemble model run */
/* Calling bash-commands inside OpenMP enviroment requires using fork().
Else the parallel process is terminated.
Note exec automatically ends the child process after termination.
If Sitra fails, the child process needs to be terminated manually */
pid_t pid = 0;
int status;
pid = fork();
if (pid == 0) {
log_info("Start SITRA for Ens %d on thread %d",i,omp_get_thread_num());
sprintf(temp,"ens_%d",i);
chdir(temp);
execl("../SPRING/sitra","sitra","-return",(char *) 0);
perror("In exec(): ");
}
if (pid > 0) {
pid = wait(&status);
log_info("End of sitra for ensemble %d",i);
if (WIFEXITED(status)) {
printf("Sitra ended with exit(%d).\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("Sitra ended with kill -%d.\n", WTERMSIG(status));
}
}
if (pid < 0){
perror("In fork():");
}
}

running a background process using a double fork?

pid = fork();
if(pid == 0 && background == 1){
// performs background process
pid2 = fork();
if(pid2 == 0){
// grandchild process
} else {
// child process
exit(0);
}
} else if(pid == 0){
// child process
} else {
//parent process
waitpid(pid, NULL, 0);
}
My question is I'm trying to perform a background process using double forks but I'm not 100% sure it works or not with the way I set it up, another question is after I double fork what is a good way to handle the orpaned children, can I just leave them or will that cause an issue? this is for a unix shell.

Emulating pipes

I've just recently learned about pipes and I would like to emulate the "|" gimmick provided by shells.
In the code below, the parent process spawns 2 child processes, after which they do their piping and get replaced by ls and grep. While that happens the parent process waits patiently. The problem is that the child processes never finish although they manage to send some data though the pipe and onto the screen.
There are other posts regarding pipes on SO, but I've never seen the setup in which the parent process launches 2 children. I've only seen the parent communicating with one child.
int p0[2];
pipe(p0); //creating pipe
if(fork() == 0) { //child 1
dup2(p0[0], STDIN_FILENO);
close(p0[0]); close(p0[1]);
execlp("grep","grep","a",NULL);
}
else { //parent
if(fork() == 0) { //child 2
dup2(p0[1], STDOUT_FILENO);
close(p0[0]); close(p0[1]);
execlp("ls","ls",NULL);
}
else { //parent
wait(NULL);
wait(NULL); //waiting for c1 and c2
close(p0[0]); close(p0[1]);
printf("parent exit\n");
}
}
My questions are: Why don't the child processes finish? Is fork-pipe structure sound or am I doing it completely wrong?
Close the pipe before starting to wait in the last section.

Doesn't print out to file using fprintf with fork()

So I've got a problem with my code and it's driving me nuts since I can't seem to figure out what's causing this. Basically, I'm trying to write to a file that I have open, using multiple child processes with fork(). Before I start forking, I can write to it just fine, but once I fork and THEN do an if statement to see if it's the child process, it won't write.
Basically, what I have is this:
FILE *output = NULL;
output = fopen(...); // Done successfully
fprintf(output, "This writes okay\n");
// Fork n processes
for (i = 0; i <= n; n++)
{
pid[i] = fork();
fprintf(output, "We can still write\n");
if (pid[i] == 0) // Child process
{
fprintf(output, "This won't write to output\n");
printf("I can still write and calculate stuff otherwise\n");
...
}
}
Can anyone figure out why it's not able to write after checking to see if it's a child process? There's definitely no error with forking from what I've seen.
Opening a file descriptor and using it in more than one process (for example in both a parent and child process) is a race condition and will most likely cause problems and unpredictable behavior.

fork() call, duplicating processes

fork() is used to create a child process...and you see this call appear in the child process as well. I don't understand what it means when they say that 'calls to fork actually return twice'.
And what does this mean...
if (fork() == 0)
/* the child process's thread executes here*/
else
/*the parent process's thread executes here*/
Is the above code part of parent or child. Can you explain in plain English what's going on?
Also, why use a fork()? It says all processes in unix run by this system call? How do you fork() so other programs can run? Do you specify the name of the program?
It's a bit like this:
Process 1 Process 2
int main() {
...
int x = goo();
...
int y = fork();
// fork() returns... // ... but also here!
// here y = 123 // here y = 0
if (y) { if (y) {
// this happens // false
} else { } else {
// false // this happens
} }
int z = baz(); int z = baz();
... ...
return 0; return 0;
} }
When Process 2 comes to life, the program exists twice, and the second process starts with the return of fork(). Since the program is the same in both processes, the only way to distinguish which process you're in is by the return value of fork().
What the mean when they say it returns twice is that the call returns once in the parent process (which called it), and once in the child process (which didn't, although you could probably argue that the child inherited the act of calling fork from the parent just like it inherited so much else).
The code snippet takes advantage of the fact that get a different return value from fork depending on whether you're the parent process or the child process.
The child process gets zero and the parent process gets the non-zero process ID of the child.
You can also get back -1 if the fork fails for some reason, in which case the child won't be running. That's something you should probably check as well.
And, while fork is used to create new processes, it's the exec family of calls which load new programs into those processes: fork on its own cannot do that.
A good overview of the process can be found here.

Resources