Using Shared Memory in Linux Programming
15 May, 2010 9 Comments
Shared memory is one way for processes to share information with each other. In the Linux environment, there are two main ways of obtaining shared memory in C or C++. The first method uses shmget to obtain an ID for the shared memory segment, then using shmat to attach the segment to the address space of the calling process. The declaration of these methods are as follows:
int shmget(key_t key, size_t size, int shmflg); void *shmat(int shmid, const void *shmaddr, int shmflg);
The parameter key identifies the shared memory segment. Two different processes should use the same key to obtain the same segment. The key could be some defined int. However, another application might be using the same key value to obtain shared memory.
Another way of obtaining the key is to use ftok. ftok generates a key value based on a file and will return the same key value when given the same file. shmget will create the shared memory segment if needed. The parameter shmflg parameter determines which permissions are assigned to the segment and how they get created. The permissions are specified in the same way as they are specified for open. See the documentation for shmget for more information about the paramter. An example of obtaining the shared memory, without checking for errors:
const char *keyFile = "/tmp/key.dat"; /* Make sure the file exists. */ int descriptor = open(keyFile, O_CREAT | O_RDWR, S_IRWXU); /* Only wanted to make sure that the file exists. */ close(descriptor); /* Generate memory key. */ key_t sharedKey = ftok(keyFile, 1); /* Get the shared memory segment id. Note we include the permissions. */ int sharedSpaceId = shmget(sharedKey, sizeof(int), IPC_CREAT | S_IRUSR | S_IWUSR); /* Attach the shared memory segment. */ int *result = (int *) shmat(sharedSpaceId, NULL, 0);
After calling shmat, result will either be -1 (this indicates an error) or pointing to the shared memory segment. If it is pointing to the shared memory segment, you can use result just like any other pointer. Since the write permission was assigned to the shared segment (at line 14), another process can attach to the same segment and read and write to it.
A second process utilitising the same could be able to access the same memory space with the same code fragment. When the process no longer needs the reference to the shared memory segment, it should detach from it. This is done by calling shmdt on the pointer. To delete the shared memory segment, use shmctl. Following from the above example, detaching and destroying the created and attachment segment:
struct shmid_ds shmid; shmctl(sharedSpaceId, IPC_RMID, &shmid) shmdt(result);
Another way of using of using shared memory is via shm_open and mmap. While shmget uses the Linux interprocess communication (IPC) facilities and creates shared memory segments in memory, shmopen creates a shared memory object based on a file. After creating the shared memory object, mmap is called to map to shared region of memory. The declarations for these methods:
int shm_open(const char *name, int oflag, mode_t mode); void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
The parameter mode specificies the permissions of the shared memory. Without the appropriate permissions set, another process will not be able to access the shared memory object. An example of obtaining shared memory using shm_open, without any of the error checking:
int *result = NULL; int integerSize = sizeof(int); /* Open the shared memory. */ int descriptor = shm_open(SHM_FILE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* Size up the shared memory. */ ftruncate(descriptor, integerSize); result = mmap(NULL, integerSize, PROT_WRITE | PROT_READ, MAP_SHARED, descriptor, 0 );
The call to ftruncate (at line 9) sets the size of the object. When it is initially created, it is initially allocated 0 bytes. After the call to mmap, the pointer result is pointing to the shared memory region. The process can now share an integer by placing it at the location at the pointer.
munmap(result, sizeof(int)); shm_unlink(SHM_FILE);