How to Use shmget to Allocate Shared Memory in C
This article will demonstrate multiple methods about using the shmget
function to allocate shared memory in C.
Use shmget
to Allocate Shared Memory in C
Shared memory is one of the ways of interprocess communication that allows two or more processes to exchange data and communicate fast in user-space. Shared memory implies that multiple processes share the same region in memory, and they can modify/access this segment as needed.
The interface we will demonstrate in the following examples is called System V shared memory, which is provided using four functions: shmget
, shmat
, shmdt
and shmctl
.
shmget
is used to create a new shared memory segment or retrieve an identifier for the already created memory segment.shmat
call is used to attach the given shared memory segment to the memory space of the calling process.shmdt
can be employed to detach the given memory segmentshmctl
is used modify and deallocate the segment with multiple options.
The next example code implements a basic usage of shmget
and shmat
functions for one process that creates a new shared segment and then writes some texts into it. The shmget
function takes three arguments, the first of which is the memory segment’s key. The key value can be IPC_PRIVATE
macro if the new segment needs to be created or the key value of the existing segment when the identifier of memory should be obtained with the call. The second argument of shmget
specifies the segment’s size and the third argument is the permission flags that can be OR-ed to include multiple values.
Once the memory segment is created, the segment identifier is obtained, and it can be passed to the shmat
function to attach the given memory. The user can pass the specific address where to attach the given memory segment as a second argument to shmat
. Still, usually, it’s preferred to let the kernel choose the address and specify NULL
to denote this.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wait.h>
enum { SEGMENT_SIZE = 0x6400 };
const char *data = "Hello there!";
int main(int argc, char *argv[]) {
int status;
int segment_id;
segment_id = shmget(IPC_PRIVATE, SEGMENT_SIZE,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
char *sh_mem = (char *)shmat(segment_id, NULL, 0);
printf("Segment ID %d\n", segment_id);
printf("Attached at %p\n", sh_mem);
memmove(sh_mem, data, strlen(data) + 1);
printf("%s\n", sh_mem);
shmdt(sh_mem);
shmctl(segment_id, IPC_RMID, 0);
exit(EXIT_SUCCESS);
}
Output:
Segment ID 1540195
Attached at 0x7f6ba1437000
Hello there!
Once the shmat
function returns the valid pointer, we can treat it as any memory address and operate on it as needed. Finally, shmdt
and shmctl
functions are called to detach the given segment and deallocate the memory. Suppose shmctl
is not called on allocated memory segments. In that case, they stay in the system’s memory after the program terminates, and it may hit the systemwide limit on the total shared memory segment.
On the other hand, the next sample code demonstrates how two processes can interact using the shared memory. The code is the same as the previous example, except that after printing the "Hello there!"
string, the main process is forked, and a child is created, which stores a different string into the same address. Meanwhile, the parent process suspends, waits for the child to terminate, and exits with success code; the newly stored string is printed to the console. If multiple processes need to modify and access shared memory segments concurrently, the programmer needs to employ some synchronization tools like semaphores.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wait.h>
enum { SEGMENT_SIZE = 0x6400 };
const char *data = "Hello there!";
int main(int argc, char *argv[]) {
int status;
int segment_id;
segment_id = shmget(IPC_PRIVATE, SEGMENT_SIZE,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
char *sh_mem = (char *)shmat(segment_id, 0, 0);
printf("Segment ID %d\n", segment_id);
printf("Attached at %p\n", sh_mem);
memmove(sh_mem, data, strlen(data) + 1);
printf("%s\n", sh_mem);
pid_t child_pid = fork();
if (child_pid == -1) perror("fork");
if (child_pid == 0) {
strcpy(sh_mem, "NEW DATA Stored by Child Process\0");
printf("child pid - %d\n", getpid());
exit(EXIT_SUCCESS);
} else {
pid_t ret = waitpid(child_pid, &status, WUNTRACED | WCONTINUED);
if (ret == -1) perror("waitpid");
if (WIFEXITED(status))
printf("Child exited, status - %d\n", WEXITSTATUS(status));
if (WEXITSTATUS(status) == 0) printf("%s\n", sh_mem);
}
shmdt(sh_mem);
shmctl(segment_id, IPC_RMID, 0);
exit(EXIT_SUCCESS);
}
Output:
Segment ID 1540195
Attached at 0x7fd825a25000
Hello there!
child pid - 27291
Child exited, status - 0
NEW DATA Stored by Child Process
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook