I am unsure if I am correctly going about this, I am trying to create 7 processes total via...
void err_sys(const char* x)
{
perror(x);
exit(1);
}
for(i = 1; i < 7; i++){
switch(parent = fork()){
case -1:
err_sys("fork error");
case 0: //child
printf("I'm the child, number %d(%d)\n", i, getpid());
break;
default: //parent
printf("I'm the parent(%d)\n", getpid());
break;
}
if(parent)
break; //loop break
}
When I run it with prog | cat > file I get 6 outputs of "I am the parent", followed with various amounts of children each. However, there are 6 children made with unique pids. The other parent pids, other than the first match a child pid. Is this just some problem that comes with output due to forking?
Your code is not incorrect a priori; it does what it does. The issue is 'does it do what you want it to do', and that is not clear because you've not clearly stated what you are trying to do.
One reason you get 6 processes is that you have a loop:
for (i = 1; i < 7; i++)
This counts 1, 2, 3, 4, 5, 6 and stops. You need to use one of two idioms:
for (i = 0; i < 7; i++) // Idiomatic C
for (i = 1; i <= 7; i++) // Less idiomatic C
Assuming that err_sys() does not return when called (if it did, you'd need a break; after it), then:
The process forks. If the fork fails, the process exits via err_sys().
If the process is the child (so the misnamed variable parent is set to 0), then the code prints "I'm the child" and then leaves the switch, and iterates around the loop again.
If the process is the parent (so the misnamed variable parent is set to a non-zero value), it prints "I'm the parent" and then leaves both the switch and the loop.
Only the child from the first fork gets to re-execute the loop. However, each child except the last gets to identify itself as the parent on the next iteration of the loop.
Buffered I/O
Note that buffered I/O complicates things. If the output of the program is written to the terminal, you will get line buffered output by default. Each newline causes the data to be written to the terminal. However, when the output goes to a pipe, it is fully buffered; the data only gets written to the terminal when the buffer is full, or the process is exiting (or closes standard output for some other reason). Thus, when the output goes to a pipe, the first child has the output from just its operations, but the second child has the data printed, but not flushed, by the first child in its buffer as well as what it wrote. The third child has 3 process's worth of output, and so on.
You could add fflush(0) or fflush(stdout) after the print statements (or just after the end of the switch, before the if) and see what a difference it makes. You can also run the code without redirecting to a pipe and see what a difference that makes.
Related
So, I've been trying to understand forks, and although I understand the basics (ie. another process gets created with a copy of the original data when we use fork()), I can't really grasp actually doing things with these processes that are created.
For example: I have to write a program that will call fork() twice to create 4 processes in total. When one process is created I have to print out the pid with getpid(). After printing out four ID's, my program is supposed to print a single letter 10 times.
For example, parent 1 will print 'A', child 1 will print 'B', child 2 will print 'C' and the parent of that will print 'D'. To do this, I have to use putchar(ch); and flush the output with fflush(stdout).
This means the output will look like this:
Process created, ID: 3856
Process created, ID: 3857
Process created, ID: 3858
Process created, ID: 3859
AAAAAABBBBBBBCDCDCDCDCDCDCBBBDCDCAAAADCD
So far, I've gotten the four processes to print with this code:
int main(void) {
pid_t child1, child2;
child1 = fork();
child2 = fork();
printf("Process created. ID: %d\n", getpid());
}
But I don't know how to use wait() to have everything print out randomly, after I have printed the ids.
To get everything I need to print out to be a "random mess," what should I do? Should I call functions like this?
// in main
for(int i = 0; i < 10; ++i) {
char_parent1();
char_child1();
char_parent2();
char_child2();
}
return 0;
}
void char_parent1()
{
putchar('A');
fflush(stdout);
}
void char_child1()
{
putchar('B');
fflush(stdout);
}
// and so on for char_parent2() and char_child2()
In that case, if my professor says I have to basically print things out concurrently and randomly, then why should I be using wait()?
Each process needs to know which letter it is supposed to print. That means you have to analyze the values in child1 and child2. For example, one process has two zeros; it might print D.
Arguably, each process needs to know whether it is a parent or not. If it is not a parent, it can simply exit after printing 10 copies of its letter, each followed by a fflush(). If it is a parent, after waiting for its children to die, it should exit. This means that the original process will exit last. It could usefully output a newline after its last child has died. You might or might not print diagnostic information about dead children as you go.
Suppose I have this code:
int main () {
int i, r;
i = 5;
printf("%d\n", i);
r = fork();
if (r > 0) {
i = 6;
}
else if (r == 0) {
i = 4;
}
printf("%d\n", i);
}
I was wondering does the forked child process start executing either from the beginning or from where it was called. The reason I ask this is because on my own system I get the output 5,6,4 which means that is starts from where it is called but typing it in http://ideone.com/rHppMp I get 5,6,5,4?
One process calls fork, two processes return (errors notwithstanding). That's how it works. So the child starts from the next "line" (technically it starts with the assignment to r).
What you're seeing here has to do with buffering. In the online case, you'll find that it's using full buffering for standard output, meaning the initial 5 hasn't yet been flushed to the output device.
Hence, at the fork, both parent and child have it and both will flush at some point.
For the line buffered case, the parent flushes on the newline so the line is no longer in the buffer at the fork.
The rules are explicit. Standard output is set to line buffered only if the output device is known to be a terminal. In cases where you redirect to a file, or catch the output in an online environment so you can sanitise it for browser output, it'll be fully buffered.
Hence why you're seeing a difference.
It's generally a good idea to flush all output handles (with fflush) before forking.
You can't judge either parent will execute first or child, in most of the cases child executes. The output should not be "5 6 5 4" might be some garbage value from buffer. You can use fflush(NULL) to flush of the buffer before fork() and try again.
Generally, your application (with its two process threads) has little to no control over how the process threads are organized on the run-queue of your OS. After fork(), there is no specific order you should expect. In fact, if your OS supports multiple CPUs, the may actually both run at the same time; which can result in some unexpected output as both processes compete for stdout.
I've been messing around in C trying to figure out how to do this. Let's say I have my main program, the parent process. The parent creates three child processes, each of which will eventually run programs (but that's not important right now). What I'd like to do is make it so that the first child's stdout will be received by the second child's stdin. The second child's stdout will then be received by the third child's stdin.
The parent process's stdin/stdout aren't messed with at all.
So far, what I've got is
pipe(procpipe);
parentPid = getpid();
for(i = 0; i < 3; i++)
{
if(getpid() == parentPid)
{
child[i] = fork();
if(child[i] == 0)
{
mynumber = i+1;
}
}
}
But from there I'm kind of stuck as to how to use dup2 to properly assign my pipes, and in which section of my code to insert it. There are lots of examples on Google and this website of how to pipe from a parent to a child, but I'm yet to see one that will tell me exactly how to connect a child's stdout to another child's stdin.
Edit:
Forgot to mention: assume all my variables are properly initialised. The int 'mynumber' is so a child process knows upon creation which number it is, so I can give it instructions via
if(mynumber == whatever)
So you have a loop that creates several child processes. Each of these child processes will be using two pipes: read from previous and write to the next. To set up a pipe for the reading end you need to close the write end of the pipe, and dup2 the read end into the stdin. Similar for the pipe where the process will be writing.
void set_read(int* lpipe)
{
dup2(lpipe[0], STDIN_FILENO);
close(lpipe[0]); // we have a copy already, so close it
close(lpipe[1]); // not using this end
}
void set_write(int* rpipe)
{
dup2(rpipe[1], STDOUT_FILENO);
close(rpipe[0]); // not using this end
close(rpipe[1]); // we have a copy already, so close it
}
When you fork each children you need to attach the pipes to it.
void fork_and_chain(int* lpipe, int* rpipe)
{
if(!fork())
{
if(lpipe) // there's a pipe from the previous process
set_read(lpipe);
// else you may want to redirect input from somewhere else for the start
if(rpipe) // there's a pipe to the next process
set_write(rpipe);
// else you may want to redirect out to somewhere else for the end
// blah do your stuff
// and make sure the child process terminates in here
// so it won't continue running the chaining code
}
}
With this in hand you can now write a loop that continuously forks, attaches the pipes, and then reuses the output pipe as the input pipe for the next one. Of course, once both ends of a pipe have been connected to child processes, the parent should not leave it open for itself.
// This assumes there are at least two processes to be chained :)
// two pipes: one from the previous in the chain, one to the next in the chain
int lpipe[2], rpipe[2];
// create the first output pipe
pipe(rpipe);
// first child takes input from somewhere else
fork_and_chain(NULL, rpipe);
// output pipe becomes input for the next process.
lpipe[0] = rpipe[0];
lpipe[1] = rpipe[1];
// chain all but the first and last children
for(i = 1; i < N - 1; i++)
{
pipe(rpipe); // make the next output pipe
fork_and_chain(lpipe, rpipe);
close(lpipe[0]); // both ends are attached, close them on parent
close(lpipe[1]);
lpipe[0] = rpipe[0]; // output pipe becomes input pipe
lpipe[1] = rpipe[1];
}
// fork the last one, its output goes somewhere else
fork_and_chain(lpipe, NULL);
close(lpipe[0]);
close(lpipe[1]);
The closing bits are very important! When you fork with an open pipe, there will be four open file descriptors: two on the parent process, and two others on the child process. You have to close all of those you won't be using. That's why the code above always closes the irrelevant ends of the pipes in the child processes, and both ends on the parent.
Also note that I am giving special treatment to the first and the last processes, because I don't know where the input for the chain will come from, and where the output will go to.
I'm writing a simple C program using fork() to create a binary tree of processes. I am able to get all the output I need (pid's of process, its parent, and its two children). Unfortunately, each forked process wants to print out the column headers. How do I make sure that the printf for the headers is executed only once?
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <unistd.h>
# include <sys/wait.h>
int main(int argc, char *argv[]){
//Declarations
int i;
int child_1_pid, child_2_pid;
int num_levels = atoi(argv[1]);
//Output banners
//execlp("/bin/echo", "echo", "Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID", (char *) NULL);
//if(getpid() > 0)
printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");
//Creates binary tree of processes
for(i = 0; i < num_levels; i++){
if((child_1_pid = fork()) && (child_2_pid = fork())){
printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);
sleep(2); //prevents parent from terminating before child can get ppid (parent's pid)
break; //why?
}
}//end for
printf("\n"); //EXPLAIN ME!!
exit(0);
}//end main
There's some more code (error checking really), but my real problem is that the printf under the output banners section executes multiple times, giving output like this (but correctly aligned):
Level Procs Parent Child1 Child2
No. ID ID ID ID
No. ID ID ID ID
No. ID ID ID ID
No. ID ID ID ID
No. ID ID ID ID
No. ID ID ID ID
No. ID ID ID ID
0 30796 24743 30797 30798
1 30797 30796 30799 30800
1 30798 30796 30801 30802
I've tried a few ideas (including those commented out under the banner section), but nothing seems to work and most "fixes" make the problem even worse!
First, the if in the for-loop does not behave as you want it to. Remember that after the fork, it returns the child PID in the parent process and 0 in the child. So inside the loop, the first fork assigns a value to child_1_pid in the parent and continues to the second clause. The child does not enter the if but continues to the next for-loop iteration. The very same happens with the second clause. So only the main process should ever be able to enter the body of the if, but no child process. I wonder why the output suggests otherwise.
So to get your "binary tree", you should actually have this:
// COMPLETELY UNTESTED
for(i = 0; i < num_levels; i++){
if (!(child_1_pid = fork()) || !(child_2_pid = fork())) {
printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);
// A child process, go on to next iteration.
continue;
}
// A parent process. Wait for children, then stop.
if (child_1_pid) wait();
if (child_2_pid) wait();
break;
}
The strange output of the banners has to do with flushing of streams. Normally, fprintf only flushed on newline (\n), IIRC. So there's still stuff in the buffer after the fork that has not been flushed yet, and each child runs printf("\n"); and thus flushes out the buffer content.
The solution is to either add a "\n" to the end of the very first printf, or call fflush(stdout); before the for loop.
Here's something to try, although I'm a little rusty with this stuff. In the line where you print out your banners:
printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");
It may be that everything after the \n is being left in the ouput buffer, so it's still there when each child is forked. Try adding another \n at the end of that printf, and removing the \n from the beginning of the printf inside the loop.
Replace:
printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");
With:
puts("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID");
Replace:
printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid);
With:
printf("%d\t%d\t%d\t%d\t%d\n", i, getpid(), getppid(), child_1_pid, child_2_pid);
Remove:
printf("\n");
Read 2.5.1 here:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
Note that after a fork(), two handles exist where one existed before. The application shall ensure that, if both handles can ever be accessed, they are both in a state where the other could become the active handle first. The application shall prepare for a fork() exactly as if it were a change of active handle. (If the only action performed by one of the processes is one of the exec functions or _exit() (not exit()), the handle is never accessed in that process.)
What this means is that, before calling fork you should call fflush on any streams that you intend to use in both processes after the fork.
System information: I am running 64bit Ubuntu 10.10 on a 2 month old laptop.
Hi everyone, I've got a question about the fork() function in C. From the resources I'm using (Stevens/Rago, YoLinux, and Opengroup) it is my understanding that when you fork a process, both the parent and child continue execution from the next command. Since fork() returns 0 to the child, and the process id of the child to the parent, you can diverge their behavior with two if statements, one if(pid == 0) for the child and if(pid > 0), assuming you forked with pid = fork().
Now, I am having the weirdest thing occur. At the beginning of my main function, I am printing to stdout a couple of command line arguments that have been assigned to variables. This is this first non assignment statement in the entire program, yet, it would seem that every time I call fork later in the program, these print statements are executed.
The goal of my program is to create a "process tree" with each process having two children, down to a depth of 3, thus creating 15 total children of the initial executable. Each process prints it's parent's process ID and its process ID before and after the fork.
My code is as follows and is properly commented, command line arguments should be "ofile 3 2 -p" (I haven't gotten to implementing -p/-c flags yet":
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
if(argc != 5)//checks for correct amount of arguments
{
return 0;
}
FILE * ofile;//file to write to
pid_t pid = 1;//holds child process id
int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have
printf("%d%d", depth, arity);
ofile = fopen(argv[1], "w+");//opens specified file for writing
int a = 0;//counter for arity
int d = 0;//counter for depth
while(a < arity && d < depth)//makes sure depth and arity are within limits, if the children reach too high(low?) of a depth, loop fails to execute
//and if the process has forked arity times, then the loop fails to execute
{
fprintf(ofile, "before fork: parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent and self id to buffer
pid = fork(); //forks program
if(pid == 0)//executes for child
{
fprintf(ofile, "after fork (child):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
a=-1;//resets arity to 0 (after current iteration of loop is finished), so new process makes correct number of children
d++;//increases depth counter for child and all of its children
}
if(pid > 0)//executes for parent process
{
waitpid(pid, NULL, 0);//waits on child to execute to print status
fprintf(ofile, "after fork (parent):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
}
a++;//increments arity counter
}
fclose(ofile);
}
When I run gcc main.c -o ptree then ptree ofile 3 2 -p, the console is spammed with "32" repeating seemingly infinitely, and the file ofile is of seemingly proper format, but far far too large for what I think my program should be doing.
Any help would be greatly appreciated.
I am not sure why the fputs to stdout would be executed for the children, and don't have a Unix box to hand to verify/test.
However, the following jumps out:
int depth = *argv[2];//depth of the process tree
int arity = *argv[3];//number of children each process should have
You are taking the ASCII codes of the first character in argv[2] and argv[3] as your depth and arity, so your code is trying to spawn 50^51 processes instead of 2^3.
What you want is:
int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have
Once you fix this, bleh[0] = depth and its twin will also need correcting.
edit Although this is not a problem right now, you're cutting it pretty close with the length of some of the things you're sprintfing into obuf. Make some of the messages just a little bit longer and Kaboom! At the very least you want to use snprintf or, better yet, fprintf into the file directly.
edit I've just realised that fork, being an OS function, most probably isn't aware of internal buffering done by C I/O functions. This would explain why you get duplicates (both parent and child get a copy of buffered data on fork). Try fflush(stdout) before the loop. Also fflush(ofile) before every fork.
You have 2 errors in your code :
1)
int depth = *argv[2];//depth of the process tree
int arity = *argv[3];//number of children each process should have
With this code you are getting the first char of the strings argv[2] and argv[3].
A correct code must be like that :
int depth = atoi(argv[2]);
int arity = atoi(argv[3]);
2)
bleh[0] = depth;
fputs(bleh, stdout);
bleh[0] = arity;
fputs(bleh, stdout);
You can do something like that bleh[0] = (char) depth; but you'll just keep the first byte of your integer and its not that you want to do i guess, if you want to print the whole integer, simply use :
printf("%d\n%d", depth, arity);
I just tryied your code with those modifications and it seems to work well :)
Anhuin
You can't print out numbers using that code at the start of your function. It's probably invoking undefined behavior by passing a non-string to fputs(). You should use sprintf() (or, even better, snprintf()) to format the number into the string properly, and of course make sure the buffer is large enough to hold the string representation of the integers.
Also, you seem to be emitting text to the file, but yet it is opened in binary mode which seems wrong.