This document provides an introduction to C/Unix multiprocess programming using fork() and execl(). It includes examples of how fork() duplicates a process, how the return value indicates the parent and child processes, how wait() pauses a parent process until a child exits, and how execl() replaces the current process with another program. It concludes with a multifork program that uses these techniques to run a command concurrently on multiple arguments.
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0 ratings0% found this document useful (0 votes)
69 views
Artigo PDF
This document provides an introduction to C/Unix multiprocess programming using fork() and execl(). It includes examples of how fork() duplicates a process, how the return value indicates the parent and child processes, how wait() pauses a parent process until a child exits, and how execl() replaces the current process with another program. It concludes with a multifork program that uses these techniques to run a command concurrently on multiple arguments.
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6
Introduction to C/Unix Multiprocess Programming - Fork and Exec
Written by: BBYUGB
Published by: Nightscript Published on: 2004-12-26 18:50:35 Topic: c We'll just go through some very simple example code, to see how to use [b]fork()[/b] and [b]execl() [/b]. 1. fork() 2. Process ID 3. wait() 4. execl() 1. fork() Basically, the fork() call, inside a process, creates an exact copy of that process somewhere else in the memory (meaning it'll copy variable values, etc...), and runs the copy fromthe point the call was made (for the assembly kids : it means that the relative value of the next instruction pointer is also copied) Now, let's take look at this : example1.c #include <stdio.h> #include <unistd.h> int main () { printf("Hello Worldn"); fork(); printf("Goodbye Cruel Worldn"); } [BBYUGB@home articledir]$ ./example1 Hello World Goodbye cruel world Goodbye cruel world [BBYUGB@home articledir]$ When we launch example1, it first goes through the first printf(). Then, the fork() makes a copy of example1. Finally, each one of example1 and its copy goes through the second printf(). 2. Process ID Just a some stuff that we need to know about PIDs : On a unix system, each time a new process is launched it is assigned a unique integer identifier. The easy way to see PIDs is to use ps : [BBYUGB@home articledir]$ ps PID TTY TIME CMD 2567 pts0 00:00:00 bash 2614 pts0 00:00:00 run-mozilla.sh 2615 pts0 00:00:05 gaim 2622 pts0 00:00:05 firefox-bin 2730 pts0 00:00:00 emacs 2752 pts0 00:00:00 ps [BBYUGB@home articledir]$ The only stuff we really need to undestand right now is that CMD is the process name, and PID its... well, PID (And don't forget to use the 'man ps' command kids). Now, here's something more about the fork() call : it returns an int. And that's the part that most people are not at ease with : The fork is executed only once, but it returns two different values. - In the copied process, called the parent (the one that made the call), it returns the PID of the copy. - In the copy, the child, it returns 0. So, the parent "knows" who his childs are, but a child doesn't "know" his parent. Moreover, by testing the return value of fork(), you can learn wich one of the parent or the child is running. example2.c #include <stdio.h> #include <unistd.h> int main () { int pid; printf("Hello Worldn"); pid =fork(); if(pid !=0) printf("I'mthe Father and my son's PID is %dn",pid); else printf("I'mthe Sonn"); printf("Goodbye Cruel Worldn"); } Note : yes, you can directly go 'if( fork() )...' instead of 'pid =fork(); if(pid !=0)' [BBYUGB@home articledir]$ ./example2 Hello World I'mthe Son Goodbye Cruel World I'mthe Father and my son's PID is 3450 Goodbye Cruel World [BBYUGB@home articledir]$ 3. wait() The wait() call is used to tell a process to wait for one of his childs to end, before going on with it's own task. wait() takes the adress of an int, in wich it puts the exit status of the child it waited for (to know what you can do with that status, look at 'man 2 wait') example3.c #include <stdio.h> #include <unistd.h> int main () { int pid, status; if(fork()) { printf("I'mthe Father, and waitingn"); pid =wait(&status); printf("I'mthe Father :n - my son's PID is %dn - my son's exit status is %dn", pid, status); }else{ printf("I'mthe Son, and sleepingn"); sleep(1); printf("I'mthe Son, and exitingn"); exit(0); } printf("Goodbye Cruel Worldn"); } [BBYUGB@home articledir]$ ./example3 I'mthe Son, and sleeping I'mthe Father, and waiting I'mthe Son, and exiting I'mthe Father : - my son's PID is 4101 - my son's exit status is 0 Goodbye Cruel World [BBYUGB@home articledir]$ Note that this time, the "Goodbye..." line is printed only once coz the child process exited before reaching the printf(). 4. execl() execve() is a way to replace the process calling it by a shell command. Here, we'll use execl(), a frontend to this command. example4.c #include <stdio.h> #include <unistd.h> int main () { printf("Calling execl...nn"); execl("/bin/cat", "cat", "./example4.c", NULL); printf("Useless call to printf"); } [BBYUGB@home articledir]$ ./example4 Calling execl... #include <stdio.h> #include <unistd.h> int main () { printf("Calling execl...nn"); execl("/bin/cat", "cat", "./example4.c", NULL); printf("Useless call to printf"); } [BBYUGB@home articledir]$ We just used execl() to replace example4 with the 'cat ./example4.c' command. The first argument of execl() is the path to the binary or the script you want to execute, and then there is the list of arguments, starting with the 0th (name of the command). The last argument must be NULL. Now, we get to the important part. multifork.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main (int ac, char * av[]) { if(ac <3) { printf("usage : multifork command arg1 arg2 ...n"); exit(EXIT_FAILURE); }else{ int i; char * command =av[1], * arg; for(i =2; i <ac; i++) { arg =av[i]; if(!fork()) execl(command, "", arg, NULL); } for(i =2; i <ac; i++) { int status; wait(&status); } exit(EXIT_SUCCESS); } } This sample primitive programtakes a path to a binary as 1st argument, and any number of arguments. It then creates a number of processes equal to the number of these arguments, and launches the command once on each argument. [BBYUGB@home articledir]$ ./multifork /bin/echo aaaa bbbbb ccccc aaaa ccccc bbbbb [BBYUGB@home articledir]$ ./multifork /bin/echo aaaa bbbbb ccccc aaaa bbbbb ccccc [BBYUGB@home articledir]$ ./multifork /bin/echo aaaa bbbbb ccccc aaaa bbbbb ccccc [BBYUGB@home articledir]$ ./multifork /bin/echo aaaa bbbbb ccccc bbbbb ccccc aaaa [BBYUGB@home articledir]$ Looking at that, we can see that the processes' execution order isn't the same each time the programis called, wich is the main advantage of using this kind of programming : the processes are executed in the same time, instead of linearly. That's all for today. As soon as I've got some time, we'll have a look at multi-threading, and maybe then we'll use all that to programa simple http-server. By the way, did I tell you about the man pages ? This is an article fromhttp://www.osix.net - view the original at: http://www.osix.net/modules/article/? id=641