Shared Memory
The interface of shared memory.
int shmget(key_t key, size_t size, int flag);
int shmctl(int shmid, int cmd, struct shmid_ds *buf );
The cmd argument specifies one of the following five commands to be performed, on the segment specified by shmid.
- IPC_STAT
- IPC_SET
- IPC_RMID
- SHM_LOCK
- SHM_UNLOCK
SHM_LOCK, SHM_UNLOCK can be executed only by superuser.
void *shmat(int shmid, const void *addr, int flag);
The address in the calling process at which the segment is attached depends on the addr
argument and whether the SHM_RND bit is specified in flag.
- If addr is 0, the segment is attached at the first available address selected by the kernel. This is the recommended technique.Unless we plan to run the application on only a single type of hardware (which is highly unlikely today), we should not specify the address where the segment is to beattached. Instead, we should specify an addr of 0 and let the system choose the address.
- If addr is nonzero and SHM_RND is not specified, the segment is attached at the address given by addr.
- If addr is nonzero and SHM_RND is specified, the segment is attached at the address given by (addr − (addr modulus SHMLBA)). The SHM_RND command stands for ‘‘round.’’ SHMLBA stands for ‘‘low boundary address multiple’’ and is always a power of 2. What
The flag argument has two possible values.
- SHM_RND
- SHM_RDONLY
int shmdt(const void *addr);
Snippets of manipulate shared memory.
#include "apue.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#define PATH "/workspace/c/apue/shm_x"
#define ID 1234
#define MESG "Oh Scent"
#define SHM_SIZE 10000
#define SHM_MODE 0600
int
shm_init(void) {
int shmid;
key_t key;
key = ftok(PATH, ID);
if (key == -1) {
err_sys("ftok failed");
}
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT|SHM_MODE)) == -1) {
err_sys("shmget failed");
}
return shmid;
}
void
shm_status(int shmid) {
struct shmid_ds shm_buf;
if (shmctl(shmid, IPC_STAT, &shm_buf) < 0) {
err_sys("shmctl failed");
}
printf("shmid: %d\n", shmid);
printf("shm_perm.uid: %d\n", shm_buf.shm_perm.uid);
printf("shm_perm.gid: %d\n", shm_buf.shm_perm.gid);
printf("shm_lpid: %d\n", shm_buf.shm_lpid);
printf("shm_cpid: %d\n", shm_buf.shm_cpid);
printf("shm_atime: %ld\n", shm_buf.shm_atime);
printf("shm_dtime: %ld\n", shm_buf.shm_dtime);
printf("shm_ctime: %ld\n", shm_buf.shm_ctime);
printf("shm_nattch: %hu\n", shm_buf.shm_nattch);
}
void
shm_set(int shmid) {
char *ptr;
ptr = shmat(shmid, 0, 0);
if (ptr == (void *) -1) {
err_sys("shmat failed");
}
strncpy(ptr, MESG, strlen(MESG));
shmdt(ptr);
}
void
shm_get(int shmid) {
char *ptr;
ptr = shmat(shmid, 0, 0);
if (ptr == (void *) -1) {
err_sys("shmat failed");
}
printf("get: %s\n", ptr);
shmdt(ptr);
}
void
shm_rm(int shmid) {
if (shmctl(shmid, IPC_RMID, 0) < 0) {
err_sys("shmctl rm failed");
}
}
int
main(void) {
int shmid;
shmid = shm_init();
shm_set(shmid);
shm_get(shmid);
shm_status(shmid);
exit(0);
}
POSIX Shared Memory
POSIX shared memory has nothing new, just using mmap combined with tmpfs file system.
shm_open + mmap