struct Buffer
{
  int GEntries;     //number of grunts to enter the shop
  int GExits;       //number of grunts to exit the shop
  int NEntries;     //number of noncoms to enter the shop
  int NExits;       //number of noncoms to exit the shop
  int OEntries;     //number of officers to enter the shop
  int OExits;       //number of officers to exit the shop
  int BarberChair;  //0, empty, 1 occupied
}
//********************
int    bufferID;          //the shared mem ID for the buffer
buffer *theBuffer;        //pointer to the shared mem area
                          //mapped as a struct of type Buffer
//********************
Ask the OS for shared memory. First parameter is a key, shows up in ipcs calls. Second parameter is the size wanted. This can be determined by the function sizeof which will return the size of a structure. Third parameter is once again, the operation and the protections. Basically, you are asking the OS to create a shared memory area of a specific size, somewhere in memory that it the OS manages, but which is owned (belongs) to the creating process.
//******************** //get shared memory if ( (bufferID = shmget( key, sizeof(buffer), (IPC_CREAT | 0644))) < 0 ) cerr << "cannot get shared memory" << endl; //********************
Creating shared memory space is not good enough. You asked the OS for it, but when you want access to the shared memory, the process needs to make it look like a well known data structure. In IPCS terminology this is attaching the shared memory . Basically, you are asking the OS to change the relationship of the created shared memory to a data structure mapped into your address space. In particular treating it as a particular structure. shmget creates shared memory and shmat maps shared memory into a process' address space. Depending on the order of actions shared memory can be created and attached before any forks, and thus since children inherit, children will automatically have the shared memory mapped to a common data structure.
//********************
// attach the shared memory, by having theBuffer point to it.
if ((theBuffer =(buffer *) shmat( bufferID, (char *)0, 0 )) == (buffer *) -1)
{
  cerr << "main cannot attach shared memory" << endl;
}
//********************
Initialization & Using Shared Memory
Happens after some process asked the OS to create the shared memory
area, and the shared memory area has been attached.
In our case the pointer theBuffer points to the shared memory
and allows the process to treat the shared memory as an instantiation
of the struct Buffer.
//********************
//* initialize the buffer
theBuffer -> GEntries = 0;     //total number of people to enter buffer
theBuffer -> GExits = 0;       //total number of people to exit buffer
for( int i=0; ichair[i] = 0;
...etc
//********************
 
Detaching  Shared Memory
Once a process is finished with the shared memory,
then the process should detach it.
Detaching, does not destroy the shared memory area, but rather
removes any mapping to that processes address space.
//********************
//* detach the buffer, all done with it
shmdt( (void *) theBuffer );
//********************
Returning Shared Memory
When all the processes are finished, then the shared memory
should be returned to the OS (be nice).
//********************
//* return shared mem
shmctl( bufferID, IPC_RMID, NULL );
//********************
Keys
In both shmget and semget
the first arg is a key.
If every user
is using the same key, either every user will get the same block of
shared memory,
or the call will fail.
A way to avoid this situation:
//********************
while( (sem=semget(++semNum,numSem,(IPC_CREAT|IPC_EXCL|0644))) == -1 )
{
    if( errno == ENOSPC )
    {
      cerr << "Failed to allocate semaphore" << endl;
      return -1;              // Failed to allocate semaphore
    }
}
//********************
The
 IPC_EXCL|IPC_CREAT
flags will cause the call to fail if a
semaphore or shared memory
associated with key,
semNum
already exists, otherwise
the creation will happen. 
Note:
semNum
is a program global that is either initialized
to 0 or to a random value, see
ftok.
Note: if you do not clean up your shared memory and semaphores
after program execution,
key conflicts are more likely to occur.
Dynamic Arrays and Shared Memory
In the following declaration the intent is to have
State
point to a dynamic array.
For shared memory, a problem exists in that the size of Buffer
does not include the shared memory, but only the integer pointer,
State.
This confuses 
shmget as documented above.
//********************
struct Buffer
{
   int *State;
};
//********************
shmget then becomes:
//********************
//get shared memory for a dynamic array of NumPhils integers
// size is determine by the number of bytes for the type NumPhils
if ( (BufferId = shmget( ++semNum, ((sizeof (int)) * NumPhils), (IPC_CREAT | 0644))) < 0 )
{
    cerr << "cannot get shared memory" << endl;
    exit (-1);
}
//********************
shmat then becomes:
//********************
// attach the shared memory, by having TheBuffer point to it, 
// where State is the pointer to the dynamic array
 
if ((TheBuffer -> State  = (int *) shmat( BufferId, (char *)0, 0 )) == (int *)
 -1)
{
   cerr << "main cannot attach shared memory" << endl;
}
Last modified September 27, 2001 by mike@cs.hmc.edu