fork ( ) - C programming - c

I'm having issues working out where a good starting point for this is,
I have made dot points on what I exactly need to do but am unsure if this is entirely possible.
I have a file that I want to run multiple instances of
I want a new ID assigned to each process for the file
I need to assign a char eg. 'A' that was given through argv[1] to a process
If there is already a process with the char given, print to stderr
So far,
what I am thinking is, having something like the function below. But i'm really not too sure,
any help would be awesomeness.
int createProcess(char *argv[]){
//argv[1] is given 'A'
//fork()
//getPID()
//assign PID to 'A'
}

I think you are looking for a combination of fork and execl. You can fork to create multiple instances and then replace one of the forked process with another process by using exec(In your case it is the same process). Through execl you can give command line arguments. You may need to use sprintf in the exec'd process and sscanf in the original process. I guess this is enough hint.

I have a file that I want to run multiple instances of
To do that you have two options :
1. You can use multiple fork() system call to duplicate new child processes and open the file in those processes.
2. You can have multiple threads in your program that open the same file.
But looking at the next three dots, fork() is the choice to go with.
I want a new ID assigned to each process for the file
When you duplicate processes using fork() each process gets its own unique process Id(pid).
I need to assign a char eg. 'A' that was given through argv[1] to a process
For this you need to use one of the many calls in the "exec" family.By using "exec"
you can also pass the command line parameters to the newly created processes.
This cannot be done by fork because fork is used to duplicate the current process, whereas if you want to create a totally new process you must use exec calls.
Edit :
In order to get the command line parameters being passed to a process, you need to
know its process id and then you can look for a directory with its name same as the pid
inside the /proc file system( not mounted on actual device ). When you find the directory
you will get the parameters passed to it in a file named "cmdline".
For more detail you can read about "/proc" file system.

You will need to create multiple forking (preferably iteratively) and index your children.* One way to do that is to let the original parent loop, and only let that process do the fork. The original parent loops k times, only creating one child process per iteration. On the created child, you do stuff only the current child process will, such as assign an identifier (such as the loop counter), perform exec, and exit after the child performs everything so it does not go to the next iteration to fork to create grandchild.
Please note that the call fork() is a syscall that causes the original process (now called parent process) to create a duplicate (called child process), as well as return an int value for the parent process only.
One thing you need to observe is that the forked processes are identical with only two exceptions: the value returned by fork() and the process pid (child usually have higher pid). The value returned on the parent is the child's PID. The value on the child process is always zero. Identifying returned value of fork() is the only way to identify it the process is a parent or child.
I have a file that I want to run multiple instances of
You may need to use a combination of fork() and exec. It is not clear which type of file you want to run. Are you reading from a file, writing from a file, or executing a file?
I want a new ID assigned to each process for the file
The PID itself is a new unique ID at the time a new process is created. However, you can use a counter so that only the parent can create multiple child processes, each with a unique ID.
I need to assign a char eg. 'A' that was given through argv[1] to a process
argv[1] is a string (char array), not a char.
If there is already a process with the char given, print to stderr
It is possible that you can keep track of all identifier chars on the original parent.
Here is some sample C code where only the parent creates the forking:
int main() {
for (int k = 1; k <= 16; k++) {
int r = fork();
if (r == 0) { // kth CHILD
printf("[%d] %d\n", getpid(), k);
exit(0);
}
else if (r > 0) {
int status;
wait(&status);
printf("[%d] P\n", getpid());
}
else return 1;
}
return 0;
}

If I understand what you want correctly is to "assign" different chars to different instances of the forked process.
You can do something like this:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]){
char chr = *argv[1];
pid_t res;
res = fork();
if (!res)
chr++;
printf("%c \n", chr);
return 0;
}

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.

How to pass arguments to processes created by fork()

I want to create copies of a process using fork() in C.
I cant figure out how to pass arguments to the copies of my process.
For example,I want to pass an integer to the process copies.
Or I what to do, if I have a loop in which I call fork() and want to pass a unique value to processes (e.g. 0...N)
for (int i = 0; i < 4; ++i) {
fork();
// pass a unique value to new processes.
}
The nice part about fork() is that each process you spawn automatically gets a copy of everything the parent has, so for example, let's say we want to pass an int myvar to each of two child processes but I want each to have a different value from the parent process:
int main()
{
int myvar = 0;
if(fork())
myvar = 1;
else if(fork())
myvar = 2;
else
myvar = 3;
printf("I'm %d: myvar is %d\n", getpid(), myvar);
return 0;
}
So doing this allows each process to have a "copy" of myvar with it's own value.
I'm 8517: myvar is 1
I'm 8518: myvar is 2
I'm 8521: myvar is 3
If you didn't change the value, then each fork'd process would have the same value.
Local and global variables are inherently preserved across a fork(), so there's no need to "pass arguments". If you're calling a function in the forked process, you can do something like:
pid_t pid = fork();
if (pid == 0) {
funcToCallInChild(argument);
exit(0);
}
I'm late to respond, but here is how I do it:
const char *progname = "./yourProgName";
const char *argument1 = "arg1";
const char *argument2 = "arg2";
if (fork() == 0)
{
// We are the child process, so replace the process with a new executable.
execl(progname, progname, argument1, argument2, (char *)NULL);
}
// The parent process continues from here.
First, you fork() the process to create a new process. It still has the same memory space as the old one. fork() returns for both parent and child processes. If fork() returns zero, you are the child process. The child process then uses execl() to replace the process memory with one from a new file.
Notice that progname is given twice to execl(). The first is what execl() will actually try to run, the second is argv[0]. You must provide both or the argument count will be off by one. Progname must contain all the required path information to find the desired executable image.
I give two arguments in this example, but you can pass as many as you want. it must be terminated with NULL, and I think you have to cast it as (char *) like I show.
This approach gives you a fully independent process with arguments and a unique pid. It can continue running long after the parent process terminates, or it may terminate before the parent.
You can use clone() (which is actually used by fork() itself). It lets you pass an arg to your entry function.
http://linux.die.net/man/2/clone
See the exec() family of functions.
EDIT: If you're trying to initialize copies of the same program as the base process, just continue using variables as suggested by duskwuff.

Can the order of execution of fork() be determined?

I'm working on an exercise on the textbook "Operating System Concepts 7th Edition", and I'm a bit confused about how does fork() work. From my understanding, fork() creates a child process which runs concurrently with its parent. But then, how do we know exactly which process runs first? I meant the order of execution.
Problem
Write a C program using fork() system call that generates the Fibonacci sequence in the child process. The number of sequence will be provided in the command line.
This is my solution:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void display_fibonacci_sequence( int n ) {
int i = 0;
int a = 1;
int b = 1;
int value;
printf( "%d, %d, ", a, b );
for( ;i < n - 2; ++i ) {
value = a + b;
printf( "%d, ", value );
a = b;
b = value;
}
printf( "\n" );
}
int main( int argc, char** argv ) {
int n;
pid_t pid;
pid = fork();
if( argc != 2 ) {
fprintf( stderr, "Invalid arguments" );
exit( -1 );
}
n = atoi( argv[1] );
if( pid < 0 ) {
fprintf( stderr, "Fork failed" );
exit( -1 );
}
else if( pid == 0 ) {
display_fibonacci_sequence( n );
}
else { // parent process
// what do we need to do here?
}
}
To be honest, I don't see any difference between using fork and not using fork. Besides, if I want the parent process to handle the input from user, and let the child process handle the display, how could I do that?
You are asking many questions, I'll try to answer them in a convenient order.
First question
To be honest, I don't see any difference between using fork and not
using fork.
That's because the example is not a very good one. In your example the parent doesn't do anything so the fork is useless.
Second
else {
// what do we need to do here?
}
You need to wait(2) for the child to terminate. Make sure you read that page carefully.
Third
I want the parent process to handle the input from user, and let the
child process handle the display
Read the input before the fork and "handle" the display inside if (pid == 0)
Fourth
But then, how do we know exactly which process runs first?
Very few programs should concern themselves with this. You can't know the order of execution, it's entirely dependent on the environment. TLPI says this:
After a fork(), it is indeterminate which process—the parent or the
child—next has access to the CPU. On a multiprocessor system, they may both simultaneously get access to a CPU.
Applications that implicitly or explicitly rely on a particular
sequence of execution in order to achieve correct results are open to
failure due to race conditions
That said, an operating system can allow you to control this order. For instance, Linux has /proc/sys/kernel/sched_child_runs_first.
We don't know which runs first, the parent or the child. This is why the parent generally has to wait for the child process to complete if there is some dependency on order of execution between them.
In your specific problem, there isn't any particular reason to use fork(). Your professor probably gave you this just for a trivial example.
If you want the parent to handle input and the child to calculate, all you have to do is move the call to fork() below the point at which you handle the command-line args. Using the same basic logic as above, have the child call display_fibonacci_sequence, and have the parent simply wait
The process which is selected by your system scheduler is chosen to run, not unlike any other application running on your operating system. The process spawned is treated like any other process where the scheduler assigns a priority or spot in queue or whatever the implementation is.
But then, how do we know exactly which process runs first? I meant the
order of execution.
There is no guarantee to which one ran first. fork returns 0 if it is the child and the pid of the child if it is the parent. Theoretically they could run at exactly the same time on a multiprocessor system. If you actually wanted to determine which ran first you could have a shared lock between the two processes. The one that acquires the lock first could be said to have run first.
In terms of what to do in your else statement. You'll want to wait for the child process to exit using wait or waitpid.
To be honest, I don't see any difference between using fork and not using fork.
The difference is that you create a child process. Another process on the system doing computation. For this simple problem the end user experience is the same. But fork is very different when you are writing systems like servers that need to deal with things concurrently.
Besides, if I want the parent process to handle the input from user, and let the child process handle the display, how could I do that?
You appear to have that setup already. The parent process just needs to wait for the child process to finish. The child process will printf the results to the terminal. And the parent process currently gets user input from the command line.
While you cannot control which process (parent or child) gets scheduled first after the fork (in fact on SMP/multicore it might be both!) there are many ways to synchronize the two processes, having one wait until the other reaches a certain point before it performs any nontrivial operations. One classic, extremely portable method is the following:
Prior to fork, call pipe to create a pipe.
Immediately after fork, the process that wants to wait should close the writing end of the pipe and call read on the reading end of the pipe.
The other process should immediately close the reading end of the pipe, and wait to close the writing end of the pipe until it's ready to let the other process run. (read will then return 0 in the other process)

fork() causes column headers to print for each process

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.

Functionality of 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.

Resources