Hello I'm trying to figure out how to use the fork method in C. (I'm new to C).
Following a tutorial I would expect the following code:
// 62-lab.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
fork(); // 1st fork, output is one line (two expected)
//fork(); // 2nd fork, output is one line (four expected)
//fork(); // 3rd fork, output is two lines (eight expected)
printf("pid: %d\n", getpid());
return 0;
}
to give me two lines with the pids from the two processes. However I only get one line as an output.
Even stranger when I call the fork() method 3 times I get two lines as a result.
Edit
I also checked if the fork is successful with the following code:
int main() {
if (fork() >= 0) {
printf("pid: %d\n", getpid());
} else {
printf("Error while forking!");
}
return 0;
}
and the output is still only one line:
$ ./a.out
pid: 51582
$
Edit 2
So it seems the problem only appears when the stdout is connected to an eshell buffer in emacs. I ran the same code in other terminal emulators and there it worked as expected. This is odd, but for now I can bypass the problem by using another terminal emulator.
Any help is appreciated.
Related
This question already has answers here:
printf anomaly after "fork()"
(3 answers)
Closed 25 days ago.
This post was edited and submitted for review 24 days ago.
I have a C programme like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("hello world (pid:%d)\n", (int)getpid());
int rc = fork();
if (rc < 0)
{ // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0)
{ // child (new process)
printf("hello, I am child (pid:%d)\n", (int)getpid());
}
else
{ // parent goes down this path (main)
printf("hello, I am parent of %d (pid:%d)\n",
rc, (int)getpid());
}
return 0;
}
After finishing the gcc compilation, I got the "a.out" executable file. And I got the correct programme output in the Linux shell.
hello world (pid:1056088)
hello, I am parent of 1056089 (pid:1056088)
hello, I am child (pid:1056089)
But if I use the watch command to execute it, I got the output like this:
hello world (pid:1056155)
hello, I am parent of 1056156 (pid:1056155)
hello world (pid:1056155)
hello, I am child (pid:1056156)
I don't know why if I use the watch command, there would be an extra line in the output.
I have tried to delete the line "printf("hello world (pid:%d)\n", (int)getpid());", there would be no difference between the outputs. And if I add the "fflush(stdout);" line under it, it also has no difference between the outputs.
Now I know that "stdout" is line buffered. But I wonder why the "watch" commmand has the diffwerent output with the "./a.out" format. Is this a bug, or a feature?
I would be appreciate if anybody can explain it to me.
When printing to a pipe, standard output is buffered. When you fork, the whole program is copied to the fork, including the contents of the buffer.
If you print more than just one line, you can see that only the final part of it gets copied and printed twice, e.g.
for (int i = 1; i < 64000; ++i) printf("%d\n", i);
On my machine, everyting up to 63970 gets printed once, the rest is printed twice:
a.out | grep 6397[01]
63970
63971
63971
See also Why does printf not flush after the call unless a newline is in the format string?
In my homework I should explain what is happening in the following code:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int x = 1;
if(fork() == 0){// child
printf("printf1: x=%d\n", ++x);// add then print
}
printf("printf2: x=%d\n", --x);
exit(0);
}
It's pretty straightforward and easy to understand. Most of the time I get the following output:
printf2: x=0
printf1: x=2
printf2: x=1
This means that the parent process was completed before the child and the child became a zombie process.
But sometimes I get the following output:
printf1: x=2
printf2: x=1
After printing that the program freezes (It does not print anything and does not stop).
I am running the program on Ubuntu.
Any explanation will be appreciated.
You have 3 processes writing to your terminal: parent, child and the shell interpreter. The parent process and the shell have "syncronized" output, but the child process may interleave its output with either of those. What you may perceive as a hanged process, may actually only be mangled output.
When you think it has hanged, you may try to enter a command and press enter...
I'm completly new to the C language and Unix systems. I might formulate myself badly or wrong. I have a C program where two processes increments a global variable up to 30. I am aware that order of output is random with parallel processing. But when using the | more pipe, the output is always the same: Child 1-30 -> Parent 1-30. How come?
I've been told that when using printf to print a variable, the variable content is sent to a buffer before printing to screen. And apparently you can use new line (\n) to flush the buffer right away. Is this information connected?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int g_ant = 0;
void writeloop(char *text)
{
long i = 0;
while (g_ant < 30)
{
if (++i % 100000 == 0)
printf("%s: %d\n", text, ++g_ant);
}
}
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
{ /* child */
writeloop("Child");
exit(0);
}
writeloop("Parent"); /* parent */
waitpid(pid, NULL, 0);
return 0;
}
Your information is basically correct.
When the output goes to the terminal, the output is line buffered. When the output goes to a pipe, the output is fully buffered, so one of the processes finishes its output first. You could add fflush(stdout) after each iteration in writeloop(), or use setvbuf() to make it line buffered, or even unbuffered output.
Incidentally, note that the global variable is not shared between the child and the parent process; they each have their own copy of the variable.
This question already has answers here:
Working of fork() in linux gcc [duplicate]
(5 answers)
Closed 9 years ago.
Simple piece of code:
#include <stdio.h>
#include <string.h>
main()
{
printf("Process");
fork();
fork();
return 0;
}
From my understanding of fork(), after this code executes we will have 3 child processes and 1 parent process. Also whenever we call fork() the execution should start from the statement immediately after the fork() statement. Hence according to me "Process" should be printed only once. But in my output Process is being printed 4 times. How is that possible?
Because the standard output is line buffered by default, when you call fork(), the output buffer is inherited by all the children processes.
There are several different ways to change this behavior:
Add a new line character at the end:
printf("Process\n");
or call fflush() to flush the output:
printf("Process");
fflush(stdout);
or change standard output to not buffered using setbuf() or setvbuf():
setbuf(stdout, NULL);
printf("Process");
Using either way, you'll see the output only once.
Note: see #Dvaid Schwartz's answer for the bug with calling atexit() multiple times in your code.
Your program has a bug. All the children return from main, causing atexit handlers to run four times. The children should call _exit.
Here's how your code should look:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
main()
{
int is_child = 0;
printf("Process");
if (fork() == 0)
is_child = 1;
if (fork() == 0)
is_child = 1;
if (is_child)
_exit(0);
return 0;
}
I have written client-sever code where I have many connections, let say each node represents different process on same machine. And to do that I have obviously use fork().
But now problem is that all results get displayed on same terminal.
I want to know is there any way such that after each fork() or process creation new terminal gets opened and all results get displayed for that process on particular terminal.
P.S: I have tried system("gnome-terminal") but it just opens new terminal but all results get displayed again on same terminal only. All new terminals are just opens and remain blank without any result.
Also I have gone through this link How to invoke another terminal for output programmatically in C in Linux but I don't want to run my program with parameters or whatever. Its should be just like ./test
Here is my code:-
for(int i=0;i<node-1;i++)
{
n_number++;
usleep(5000);
child_pid[i]=fork();
if(!child_pid[i])
{
system("gnome-terminal");
file_scan();
connection();
exit(0);
}
if(child_pid[i]<0)
printf("Error Process %d cannot be created",i);
}
for(int i=0;i<node-1;i++)
wait(&status);
So basically what I want is for each process there should be new terminal displaying only that process information or result.
What I exactly want:
After fork() I have some data related to say process 1 then I want its output to one terminal
Same goes with each process. So its like if I have 3 process then there must be 3 terminals and each must display process related data only.
I know it can be doable using IPC(Inter Process Communication) but is there any other way around? I mean just 2-3 commands or so? Because I do not want to invest too much in coding this part.
Thanks in advance!!!
Maybe you want something like that. This program is using the unix98 pseudoterminal (PTS), which is a bidirectional channel between master and slave. So, for each fork that you do, you will need to create a new PTS, by calling the triad posix_openpt, grantpt, unlockpt at master side and ptsname at slave side. Do not forget to correct the initial filedescriptors (stdin, stdout and sdterr) at each side.
Note that is just a program to prove the concept, so I am not doing any form of error check.
#define _XOPEN_SOURCE 600
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <fcntl.h>
int main() {
pid_t i;
char buf[10];
int fds, fdm, status;
fdm = posix_openpt(O_RDWR);
grantpt(fdm);
unlockpt(fdm);
close(0);
close(1);
close(2);
i = fork();
if ( i != 0 ) { // father
dup(fdm);
dup(fdm);
dup(fdm);
printf("Where do I pop up?\n");
sleep(2);
printf("Where do I pop up - 2?\n");
waitpid(i, &status, 0);
} else { // child
fds = open(ptsname(fdm), O_RDWR);
dup(fds);
dup(fds);
dup(fds);
strcpy(buf, ptsname(fdm));
sprintf(buf, "xterm -S%c/2", basename(buf));
system(buf);
exit(0);
}
}