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