Tech Today

POSIX Message Passing in Linux in [C]

Posted on: May 15, 2009

REQUIRES:

Compiling a [C] program in Linux

POSIX Message passing is supported in Unix, Linux, Mac OS X and many more.

The example shown here was derived in Ubuntu 9.04 using the Jaunty Jackalope Kernel Version: 2.6.28-11.

Okay, so first question what exactly is POSIX Message passing and why should I use it?

Well, POSIX stands for “Portable Operating System Interface for Unix” and it is a collection of standards governed by the IEEE.

Message passing is all about processes being able to communicate and synchronize with one another. Why do process need to communicate with one another? Well sometimes processes hold data that other processes may need. This doesn’t just hold true for process though, think about the World Wide Web. Computers need to be able to communicate with one another all the time, so wouldn’t it be nice to have some kind of mechanism in place that demonstrates that functionality? Yeah, I thought so too.

Well here is an example of processes communication utilizing the POSIX API. Think of it as like a client – server relationship; if that helps…

Overview:

Basically four external process will be communicating with a central process relaying temperature data back and forth. The goal here is to get all the processes to have the same temperature. Once that happens the central process will send a message indicating the system is stable and the processes can print out their final temp and end. Until the system is stable the external and central processes will continue to calculate new temperatures and relay them back and forth. [NOTE]: The four external processes are only aware of the central process, but the central process is aware of all the processes.

This starts by utilizing msgget(); This function will request a message queue ID using the mailbox name provided or create one if not existent previously.

Then use msgsnd(); to relay a message to a particular mailbox and use msgrcv(); the get a message from a mailbox.

First the “server side” code:

#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define CENTRAL_MAILBOX 1200    //Central Mailbox number 
#define NUM_PROCESSES 4           //Total number of external processes

struct {
long priority;         //message priority
int temp;             //temperature
int pid;                //process id
int stable;            //boolean for temperature stability
} msgp, cmbox;

//MAIN function
int main(int argc, char *argv[]) {

   //Validate that a temperature was given via the command line
   if(argc != 2) {
      printf("USAGE: Too few arguments --./central.out Temp");
      exit(0);
   }

   printf("\nStarting Server...\n");

   //Set up local variables
   int i,result,length,status;             //counter for loops
   int uid = 0;                               //central process ID
   int initTemp = atoi(argv[1]);        //starting temperature
   int msqid[NUM_PROCESSES];       //mailbox IDs for all processes
   int unstable = 1;          //boolean to denote temp stability
   int tempAry[NUM_PROCESSES];   //array of process temperatures

   //Create the Central Servers Mailbox
   int msqidC = msgget(CENTRAL_MAILBOX, 0600 | IPC_CREAT);

   //Create the mailboxes for the other processes and store their IDs
   for(i = 1; i <= NUM_PROCESSES; i++){
      msqid[(i-1)] = msgget((CENTRAL_MAILBOX + i), 0600 | IPC_CREAT);
   }

   //Initialize the message to be sent
   msgp.priority = 1;
   msgp.pid = uid;
   msgp.temp = initTemp;
   msgp.stable = 1;

   /* The length is essentially the size 
       of the structure minus sizeof(mtype) */
   length = sizeof(msgp) - sizeof(long);

   //While the processes have different temperatures
   while(unstable == 1){
      int sumTemp = 0;        //sum up the temps as we loop
      int stable = 1;            //stability trap

      // Get new messages from the processes
      for(i = 0; i < NUM_PROCESSES; i++){
         result = msgrcv( msqidC, &cmbox, length, 1, 0);

         /* If any of the new temps are different from the old temps
             then we are still unstable. Set the new temp to the
             corresponding process ID in the array */
         if(tempAry[(cmbox.pid - 1)] != cmbox.temp) {
            stable = 0;
            tempAry[(cmbox.pid - 1)] = cmbox.temp;
         }

         //Add up all the temps as we go for the temperature algorithm
         sumTemp += cmbox.temp;
      }

      //When all the processes have the same temp twice:
      // 1) Break the loop
      // 2) Set the messages stable field to stable
      if(stable){
         printf("\Temperature Stabilized: %d\n", msgp.temp);
         unstable = 0;
         msgp.stable = 0;
      }
      else { //Calc a new temp and set the temp field in the message
         int newTemp = (2 * msgp.temp + sumTemp) / 6;
         msgp.temp = newTemp;
      }

      /* Send a new message to all processes 
          to inform of new temp or stability */
      for(i = 0; i < NUM_PROCESSES; i++){
         result = msgsnd( msqid[i], &msgp, length, 0);
      }
   }

   printf("\nShutting down Server...\n");

   //Remove the mailbox
   status = msgctl(msqidC, IPC_RMID, 0);

   //Validate nothing when wrong when trying to remove mailbox
   if(status != 0){
      printf("\nERROR closing mailbox\n");
   }
}

Next the “client side” external processes:

#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define CENTRAL_MAILBOX 1200    //Central Mailbox number

struct {
long priority;        //message priority
int temp;            //temperature
int pid;               //process id
int stable;          //boolean for temperature stability
} msgp, cmbox;

//MAIN function
int main(int argc, char *argv[]) {

   /* Validate that a temperature and a Unique 
       process ID was given via the command  */
   if(argc != 3) {
      printf("USAGE: Too few arguments --./central.out Temp UID");
      exit(0);
   }

   //Setup local variables
   int unstable = 1;
   int result, length, status;
   int initTemp = atoi(argv[1]);
   int uid = atoi(argv[2]);

   //Create the Central Servers Mailbox
   int msqidC = msgget(CENTRAL_MAILBOX, 0600 | IPC_CREAT);

   //Create the mailbox for this process and store it's IDs
   int msqid = msgget((CENTRAL_MAILBOX + uid), 0600 | IPC_CREAT);

   //Initialize the message to be sent
   cmbox.priority = 1;
   cmbox.pid = uid;
   cmbox.temp = initTemp;
   cmbox.stable = 1;

   /* The length is essentially the size of 
       the structure minus sizeof(mtype) */
   length = sizeof(msgp) - sizeof(long);

   //While all the processes have different temps
   while(unstable == 1){
      //Send the current temp to the central server
      result = msgsnd( msqidC, &cmbox, length, 0);

      //Wait for a new message from the central server
      result = msgrcv( msqid, &msgp, length, 1, 0);

      //If the new message indicates all the processes have the same temp
      //break the loop and print out the final temperature
      if(msgp.stable == 0) {
         unstable = 0;
         printf("\nProcess %d Temp: %d\n", cmbox.pid, cmbox.temp);
      }
      else { //otherwise calculate the new temp and store it
         int newTemp = (cmbox.temp * 3 + 2 * msgp.temp) / 5;
         cmbox.temp = newTemp;
      }
   }

   //Remove the mailbox
   status = msgctl(msqid, IPC_RMID, 0);

   //Validate nothing when wrong when trying to remove mailbox
   if(status != 0){
      printf("\nERROR closing mailbox\n");
   }
}

START YOUR ENGINES:

Run each process in a separate terminal like so:

./external.out 100 1

./external.out 22 2

./external.out 50 3

./external.out 40 4

./central.out 60

OUTPUT:

lee@isis:~$ ./central.out 60

Starting Server...

Temperature Stabilized: 49

Shutting down Server...

lee@isis:~$ ./external.out 100 1

Process 1 Temp: 49

lee@isis:~$ ./external.out 22 2

Process 2 Temp: 49

lee@isis:~$ ./external.out 50 3

Process 3 Temp: 49

lee@isis:~$ ./external.out 40 4

Process 4 Temp: 49

Congratulations, you have just experienced process communication. Now, where can you take this mechanism from here?

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: