Cleanup of shared memory segments used by multiple processes

One way to synchronize multiple processes is to use shared memory segments:

/* get id of shared memory segment with key shmkey - if not existing, create one */
int shmid = shmget(shmkey, size, IPC_CREAT | S_IRUSR | S_IWUSR);
/* attach the shared memory segment */
void *mem = shmat(shmid, 0, 0);
/* do some read/write stuff on shared memory */
/* detach shared memory segment */
shmdt(mem);
/* 'remove' shared memory segment */
shmctl(shmid, IPC_RMID, NULL);

The last step will not remove the shared memory segment immediately. It will mark the shared memory segment as to be deleted. If all processes are detached, the shared memory segment is deleted.

So the question is, can we can use that behaviour as is for an automatic cleanup of a shared memory segment, if we think of multiple in parallel running processes with different starting times.

The answer is no, because shmget will never give you a shared memory segment, which has been marked for deletion. Instead you either will get a new one, if you use it with IPC_CREAT, or an error otherwise.

Let’s have a look on an example. Imagine we have a process which reads a number from the shared memory, if there is no one yet it writes one. All parallel running processes shall use the same number. We will end up with:

Sequence Diagram: Destruction and Attachment of Shared Memory Segments
Destruction and Attachment of Shared Memory Segments

You can see , that there is a time frame in which two parallel processes using different values. The 2nd process uses 6 while the 3rd process uses 3.

You can see this behaviour also on console by using ipcs:

After shmget with key 0x0001b207 for a not existing memory segment:

$ ipcs -m
------ Shared Memory Segments --------
key        shmid   bytes    nattch status
0x0001b207 5242900 26687216 5

After ‘deletion’ of the memory segment, the segment is marked for deletion and its key is nulled:

$ ipcs -m
------ Shared Memory Segments --------
key        shmid   bytes    nattch status
0x00000000 5242900 26687216 3      dest

shmget with key 0x0001b207 as in the beginning results in a new created memory segment:

$ ipcs -m
------ Shared Memory Segments --------
key        shmid   bytes    nattch status
0x00000000 5242900 26687216 3      dest
0x0001b207 5275669 26687216 2

So finally, to implement the wanted behaviour, we have to implement something around this.

Either we check the number of attachments and only delete the shared memory segment, if no process is attached anymore. Then we will have a short time frame between get and delete in which new attachments could have been done. So you will need a kind of locking here.

Or alternatively, we can do a shmget only if no shared memory for the key exists. In this case, if a shared memory segment already exists, we only attach to the shared memory using its id without doing a  shmget before. But of course this means that we have to store the id of the shared memory segment (e.g. in a file), so that a new started process can get it.

Leave a Reply

Your email address will not be published. Required fields are marked *