Wednesday, December 21, 2005

fork()

Several months ago, I got very interested in Linux processes, socket programming, and IPC. While I was very familiar with the concepts themselves, I had never actually written programs that utilized them. In this article, I will look at the simpler of the topics, using the Linux fork() function to generate a new process.

fork() is surprisingly easy to use. Simply make a call to fork, and you have a new process. The return from fork() is the process ID of the child ID. In the child process, the returned value is 0. This makes storing the returned value from fork necessary to determine while process is active. For example, if I have this function call:

pid = fork();

pid in the parent process will be assigned the value of the child process ID, and inside the child process, pid will be assigned 0. I really thought there would be more to it, but in a nutshell, that is basically it. Below is an example program. The program will fork a process. The parent will count to 100 by 2, starting at 0, and the child will count to 101 starting at 1. Both will display to the same console, so the output will need to identify itself as the child or parent process. The example was compiled with GCC under Cygwin with no problems.

//Two C headers needed for the process ID type and the system calls to fork processes
#include <sys/types.h>
#include <unistd.h>

//I prefer the C++ style IO over the C style
#include <iostream>

//Needed to call IOSTREAM in the standard namespace without prefix
using namespace std;

int main()
{
     //variable to store the forked process ID
     pid_t process_id;
     //counter to be used in the loops
     int counter;

     //Fork the process ID, and if there is an error, exit the program with an error
     process_id = fork();
     if (process_id < 0)
     {
          cerr << "Process failed to create!" << endl;
          exit(1);
     }
     
     //If the process ID is not 0, it is the parent process. The parent process will counter from 0 to 100 and increment
     //by two each time. The child process will have a process_id of 0, and increment by 2 starting from 1.
     if (process_id)
     {
          //Let the user know what the parent ID is and the generated child ID
          cout << "I am the parent ID. My PID is: " << getpid() << " and my Childs process ID is " << process_id << endl;
          for (counter = 0; counter <= 100; counter += 2)
          {
               cout << "Parent (" << getpid() << "): " << counter << endl;
          }
     }
     else
     {
          //Tell the user what the current process ID is using getpid to verify it is the child process, then show
          //that process_id is 0
          cout << "I am the Child ID " << getpid() << " and I think the assigned process ID is " << process_id << endl;
          for (counter = 1; counter <= 101; counter += 2)
          {
               cout << "Child(" << getpid() << "): " << counter << endl;
          }
     }

     return 0;
}

Being able to spawn separate processes is incredible useful in handling multiple connection in a server program. Sharing variables between multiple processes gets really interesting. This is where the various IPC methods come in to play, but that’s for another article.

No comments: