I'm trying to learn UNIX programming and came across a question regarding fork() and I couldn't interpret the output of the 2 programs below.
I understand that fork() creates an identical process of the currently running process, but where does it start? For example, if I have these two programs below, what will be the output and how does it work ?
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int retval;
printf ("This is most definitely the parent process\n");
// now here fork will create a child process
// i need to know from which line child process starts execution
retval = fork ();
printf ("Which process printed this?\n");
return (0);
}
What will be the difference in above program and the one below with
respect to child process execution:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int retval;
printf ("This is most definitely the parent process\n");
fflush (stdout);
// how does fflush change the output of above program and why ?
// even though no string operations are being used
retval = fork ();
printf ("Which process printed this?\n");
return (0);
}
I think both of them should print :
This is most definitely the parent process
Which process printed this?
Which process printed this?
But the first one is printing:
This is most definitely the parent process
Which process printed this?
This is most definitely the parent process
Which process printed this?
I understand that fork() creates an identical process of the currently
running process, but where does it start?
If fork(2) is successful (i.e. does not return -1), it starts in the line that calls fork(2). fork(2) returns twice: it returns 0 in the child, and a positive number C in the parent, where C is the process ID of the newborn child.
The reason you're seeing This is most definitely the parent process twice is related to stdio's buffering. Stdio buffers output in userspace buffers that are flushed only when some condition occurs (for example, the buffer becomes full). The buffering mode dictates when and how buffers are flushed.
Usually, if output is being written to an interactive device such as a terminal (or pseudoterminal), stdio is line-buffered, which means that the buffers are flushed when a newline is found or fflush(3) is called.
OTOH, if output is redirected to a file or other non-interactive devices (for example, output is redirected to a pipe), stdio is fully-buffered, which means that buffers are flushed only when they become full or fflush(3) is called.
So, without fflush(3), executing the code in a terminal device will print this:
This is most definitely the parent process
Which process printed this?
Which process printed this?
Which is expected. However, if you pipe it through cat(1), you will see this (or some other variant, depends on execution order):
This is most definitely the parent process
Which process printed this?
This is most definitely the parent process
Which process printed this?
This is because output is fully buffered when redirected to a pipe. The string This is most definitely the parent process isn't enough to fill and flush the buffer, so when the parent forks, the child (which gets a copy of the parent's memory space) will get a copy of the output buffer, which already contains the string This is most definitely the parent process. So both processes end up printing that string.
If you always call fflush(3) before forking, this won't happen because the buffer is empty when the parent's memory space is copied to the child.
Execution will continue at (or just after) the fork call. You can use the return value to check if you're the parent or the child process:
RETURN VALUE
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.
(Source: man fork)
For example, if you have the following program:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv) {
printf("Foo.\n");
int retval = fork();
printf("Bar from %s (%d).\n", (retval == 0) ? "child" : "parent", retval);
return 0;
}
The output would be something like:
Foo.
Bar from parent (18464).
Bar from child (0).
...assuming output is line buffered.
when calling fork() there are three possible return conditions.
Do read the man page for fork()
the three return conditions are
-1 -- the fork() failed
0 -- the child is executing
some positive number -- the pid of the child, the parent is executing
The code needs to be something like this:
pid_t pid;
pid = fork();
if ( 0 > pid )
{ // then handle error
}
else if ( 0 == pid )
{ // then child executing
}
else // if ( 0 < pid )
{ // then parent executing
}
Related
The task is as follows
Write a program that would run another process in memory and leave it running in an infinite loop. When the program is restarted, it must remove the previously started process from memory (you can use kill).
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <spawn.h>
#include <sys/wait.h>
int main(void){
int pid = getpid(); // we find out the PID of the current process and store it in a variable
FILE *file = fopen("example.txt", "r"); // getting information from a file about a child process
int filePid = 0;
fscanf(file, "%d", filePid);
fclose(file);
switch (filePid){
case -1:{ // if there is no child process, then run it and write the PID to a file
filePid = fork();
file = fopen("example.txt", "w");
fprintf(file, "%d", filePid);
fclose(file);
break;
}
case 0:{ // if this process is a child, then we go into an infinite loop
for(;;){
sleep(7); // waiting for seven seconds so that the system is not heavily loaded
}
break;
}
default:{ // if this program is started again with a child process, then we send a signal to the child process
kill(filePid, SIGKILL); // we send a signal to the child process so that it ends, and after that we write the information to the file
file = fopen("example.txt", "w"); // we write information to the file that the child process is missing
fprintf(file, "%d", -1);
fclose(file);
}
}
return EXIT_SUCCESS;
}
/Yes, I have to do it through the qnx operating system./
the errors are as follows..I'm a little confused with getpid, because I haven't used the pid variable anywhere.
and another mistake.
I will be grateful for your help.since I'm a little confused...
UPD:
I can't get the value 0
UPD: how could it execute both cases, i mean "if" and "else" blocks at the same time?
how could it execute both cases, i mean "if" and "else" blocks at the same time?
You have to have a clear understanding of how fork works, when you use fork two identical processes are created parent and child and they run simultaneously, when you say filePid = fork() and if the operation is successful then the parent process will hold the process id of the child process and child process will hold 0. So here in parent process filePid == child process ID and in child process filePid == 0.
See man 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 whatever you put in the if (filePid == 0) block will be executed by the child process and whatever you put in the else block will be executed by the parent process simultaneously.
This will be helpful if you want to know more about fork.
fork() system call creates a child process and return its pid so once child is created you have two process running same instruction after fork() one is checking pid is greater which means its parent which gets child pid and in child context OS will set the pid value to 0 so it will enter condition block intended for child
I'm new in Unix systems programming and I'm struggling to understand file descriptors and pipes. Let's consider this simple code:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main() {
int fd[2], p;
char *m = "123456789\n", c;
pipe(fd);
p = fork();
if (p == 0) {
// child
while(read(fd[0], &c, 1) > 0) write(1, &c, 1);
}
else {
// parent
write(fd[1], m, strlen(m));
close(fd[1]);
wait(NULL);
}
exit (0);
}
When I compile and run the code, it outputs 123456789 but the process never ends unless I issue ^C. Actually, both processes appear as stopped in htop.
If the child closes fd[1] prior to read() then it seems to work OK but I don't understand why. The fd are shared between both processes and the parent closes fd[1] after writing. Why then the child doesn't get the EOF when reading?
Thank you in advance!
Well, first of all your parent process is waiting for the child to terminate in the wait(2) system call, whyle your child is blocked in the pipe to read(2) for another character. Both processes are blocked... so you need to act externally to take them off. The problem is that the child process doesn't close it's writing descriptor of the pipe (and also the parent doesn't close its reading descriptor of the pipe, but this doesn't affect here) Simply the pipe blocks any reader while at least one such writing descriptor is still open. Only when all writing descriptors are closed, the read returns 0 to the reader.
When you did the fork(2) both pipe descriptors (fd[0] and fd[1]) were dup()ed on the child process, so you have a pipe with two open file descriptors (one in the parent, one in the child) for writing, and two open descriptors (again, one in the parent, one in the child) for reading, so as one writer remains with the pipe open for writing (the child process in this case) the read made by the child still blocks. The kernel cannot detect this as an anomaly, because the child could still write on the pipe if another thread (or a signal handler) should want to.
By the way, I'm going to comment some things you made bad in your code:
first is that you consider only two cases from fork() for the parent, and for the child, but if the fork fails, it will return -1 and you'll have a parent process writing on a pipe with no reading process, so probably it should block (as I say, this is not your case, but it is an error either) You have always to check for errors from system calls, and don't assume your fork() call is never to fail (think that -1 is considered != 0 and so it falls through the parent's code). There's only one system call that you can execute without checking it for errors, and it is close(2) (although there's much controversy on this)
This same happens with read() and write(). A better solution to your problem would be to have used a larger buffer (not just one char, to reduce the number of system calls made by your program and so speed it up) and use the return value of read() as a parameter on the write() call.
Your program should (it does on my system, indeed) work with just inserting the following line:
close(fd[1]);
just before the while loop in the child code, as shown here:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main() {
int fd[2], p;
char *m = "123456789\n", c;
pipe(fd);
p = fork();
if (p == 0) {
// child
close(fd[1]); // <--- this close is fundamental for the pipe to work properly.
while(read(fd[0], &c, 1) > 0) write(1, &c, 1);
}
else if (p > 0) {
// parent
// another close(fd[0]); should be included here
write(fd[1], m, strlen(m));
close(fd[1]);
wait(NULL);
} else {
// include error processing for fork() here
}
exit (0);
}
If the child closes fd[1] prior to read() then it seems to work OK but I don't understand why.
That's what you need to do. There's not much more to it than that. A read from the read end of a pipe won't return 0 (signaling EOF) until the kernel is sure that nothing will ever write to the write end of that pipe again, and as long as it's still open anywhere, including the process doing the reading, it can't be sure of that.
After forking and executing a child program by function execvp(), the parent process exit. However this cause the function fgets() in the child process return immediately without waiting for input from stdin.
I guess the exiting of the parent process will send some signals to the child process which make the fgets() function return. Could some one explain more for me?
Code of child program:
/* cc child.c -o child */
int main () {
char buffer[10];
fgets(buffer, 10, stdin);
printf("This is what child program read:\n%s", buffer);
}
Code of parent program:
/* cc parent.c -o parent */
int main (int argc, char **argv) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0) {
execvp(*(argv+1), argv+1);
}
else {
// while(1); if while(1) or wait() is used, child process can wait for input
exit(1);
}
}
In zsh shell:
zsh>: ./parent ./child
zsh>: This is what child program read: // read nothing and print nothing
The terminal is controlled by the foreground process group. When the shell invokes the parent, it makes the parent the leader of the foreground process group. The child inherits that group and has access to the terminal.
However, when the parent exits, the shell takes back control of the terminal and becomes the leader of the foreground process group. The child is no longer in the foreground process group, so it has no access to the terminal. In this case, fgets() will return NULL and an error code will be set.
If you take input from someplace other than the terminal, such as a pipe, then you'll see that the program works as expected. For example:
$ echo test | ./parent ./child
So this problem only occurs when input comes from the terminal.
In retrospect, answering this question would have been more straighforward if the fgets error code was checked. In this case, fgets returns null, but then you need to check feof() and/or ferror() to determine if this means that the end of the file was reached (stdin closed) or there was an error. In this case, the NULL meant there was an EIO error.
Earlier wrong answer (see comment thread for explanation, leaving this here because of the lengthy discussion):
When you fork, the child process inherits stdin etc. When the parent process exits, it closes stdin, so the child tries to read from a closed descriptor and gets nothing. By adding the call to wait(), you keep stdin open and this allows your child program to work as expected.
You should check the return value from fgets() before printing buffer. Check if fgets doesnot return NULL, and then only print the buffer.
I'm working on a C program in Xcode on OSX.
The (parent) program has to launch a new (child) process which receives its input via stdin and outputs results to stdout. So the parent writes data to the child process's stdin and the parent reads results from the child process's stdout.
On Windows I use CreateProcess to do the above, but I'm not sure how it's done on OSX in C.
I believe I'm supposed to use exec to start the process, but I don't see how I redirect stdin and stdout of the executable (child process) which exec starts. And from reading the manual it also looks like the child process will become the parent process if I use exec. The child and parent process has to run in parallel so that the parent process can write and read to the child process when it needs to.
Is there a kind OSX C expert out there who could give me a brief example of how the above is done?
Thanks
EDIT
I think I understand. But if the child process is an infinite while-loop which waits for input on stdin, then it won't turn into a "zombie", right?
The child process basically does this:
1. Read data from stdin (i.e. blocked until data is received)
2. Process data
3. Write result to stdout
4. Goto 1
After I read your post, I found this page:
http://www.jukie.net/~bart/snippets/popenRWE/popenRWE.c.html
However, I'm having a problem getting my .exe (child process) to launch
In a terminal, I would start the .exe like this:
./myApp.exe someParam1 someParam2 someParam3
The API looks like this:
popenRWE(int *rwepipe, const char *exe, const char *const argv[])
I'm guessing that the second argument should be:
const char* exe = "./myApp.exe";
and that the third argument should be:
char* p0 = "./myApp.exe";
char* p1 = "someParam1";
char* p2 = "someParam2";
char* p3 = "someParam3";
char** argv[4] = {p0, p1,p2,p3};
Am I right?
I'm including the source of a small library I've written a while ago. That should get you started. Fork / pipe / exec isn't really that easy (especially with all the variants of exec) and it took me a while too. So here goes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "limbo.h"
int out_pipe[2], err_pipe[2];
int run_command(char *argv[], int *out_length, int *err_length){
pid_t pid;
int status = 0;
struct stat out_stat, err_stat;
pipe(out_pipe); //create a pipe
pipe(err_pipe);
if(!(pid = fork())) //spawn child
{
// Child. Close the read end of the pipe
close(out_pipe[0]);
close(err_pipe[0]);
// redirect stdout and stderr to the write end of the pipe
dup2(out_pipe[1], STDOUT_FILENO);
dup2(err_pipe[1], STDERR_FILENO);
status = execv(argv[0], argv); //child will terminate here
}
//Only parent gets here. Close write end of the pipe
close(out_pipe[1]);
close(err_pipe[1]);
//or wait for the child process to terminate
waitpid(pid, &status, 0);
fstat(out_pipe[0], &out_stat);
fstat(err_pipe[0], &err_stat);
*out_length = (int) out_stat.st_size;
*err_length = (int) err_stat.st_size;
return status;
}
int read_buffers(char *out_buffer, int out_length, char *err_buffer, int err_length){
out_buffer[read(out_pipe[0], out_buffer, out_length)] = 0;
err_buffer[read(err_pipe[0], err_buffer, err_length)] = 0;
return 0;
}
The comments in the code should help you to understand the code. Feel free to reuse.
Edit
In response to your comment:
The waitpid() call makes the parent process wait for the termination of the child process. If you want both processes to run in parallel, you need to get rid of waitpid() in the place that I use it. But be careful: without a call to one of the wait functions your child process will become a zombie once it finishes. It is your responsibility to keep an eye on your child process and to wait for it so the process can be cleaned up by the kernel.
Consider the code:
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
/* main --- do the work */
int main(int argc, char **argv)
{
pid_t child;
if ((child = fork()) < 0) {
fprintf(stderr, "%s: fork of child failed: %s\n",
argv[0], strerror(errno));
exit(1);
} else if (child == 0) {
// do something in child
}
} else {
// do something in parent
}
}
My question is from where does in the code the child process starts executing, i.e. which line is executed first??
If it executes the whole code, it will also create its own child process and thing will go on happening continuously which does not happen for sure!!!
If it starts after the fork() command, how does it goes in if statement at first??
It starts the execution of the child in the return of the fork function. Not in the start of the code. The fork returns the pid of the child in the parent process, and return 0 in the child process.
When you execute a fork() the thread is duplicated into memory.
So what effectively happens is that you will have two threads that executes the snippet you posted but their fork() return values will be different.
For the child thread fork() will return 0, so the other branch of the if won't be executed, same thing happens for the father thread.
When fork() is called the operating system assigns a new address space to the new thread that is going to spawn, then starts it, they will both share the same code segment but since the return value will be different they'll execute different parts of the code (if correctly split, like in your example)
The child starts by executing the next instruction (not line) after fork. So in your case it is the assignment of the fork's return value to the child variable.
Well, if i understand your question correctly, i can say to you that your code will run as a process already.When you run a code,it is already a process , so that this process goes if statement anyway. After fork(), you will have another process(child process).
In Unix, a process can create another process, that's why that happens.
Code execution in a child process starts from the next instruction following the fork() system call.
fork() system call just creates a seperate address space for the child process therefore it is a cloned copy of the parent process and the child process has all the memory elements of it's parent's process.
Thus, after spawning a child process through fork(), both processes (the parent process and the child process) resumes the execution right from the next instruction following the fork() system call.