[TOC] 1. 概述 System V共用記憶體在概念上類似於Posix共用記憶體,代之以調用shm_Open後調用mmap的是,先調用shmget,再調用shmat。 對於每個System V共用記憶體,內核都維護如下的信息結構,它定義在sys/shm.h頭文件中,其中帶註釋的是我們需要關註的成員。 ...
目錄
1. 概述
System V共用記憶體在概念上類似於Posix共用記憶體,代之以調用shm_Open後調用mmap的是,先調用shmget,再調用shmat。
對於每個System V共用記憶體,內核都維護如下的信息結構,它定義在sys/shm.h頭文件中,其中帶註釋的是我們需要關註的成員。
struct shmid_ds
{
struct ipc_perm shm_perm;
size_t shm_segsz; //共用記憶體區大小
pid_t shm_lpid;
pid_t shm_cpid;
shmatt_t shm_nattch;
shmat_t shm_cnattch;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
};
2. System V共用記憶體API
shmget
shmget用於創建一個新的共用記憶體或打開一個已存在的共用記憶體。
//成功返回共用記憶體標識符,
int shmget(key_t key, size_t size, int oflag);
- 參數size是共用記憶體區大小,其餘兩個參數含義及用法和System V信號量一樣
- 當實際操作為創建新的共用記憶體時,該記憶體區size個位元組均被初始化為0
- 當實際操作為打開已有共用記憶體時,size可設為0,oflag設為需要的讀寫許可權
shmat
shmat用於把shmget創建或打開的共用記憶體連接到調用進程的地址空間。
//成功返回映射區起始地址,失敗返回-1
void *shmat(int shmid, const void *shmaddr, int flag);
- shmid是shmget返回的標識符
- shmaddr推薦設為NULL,表示由系統決定映射區起始地址
- flag一般設為0,因為只要調用進程具有共用記憶體的讀寫許可權,那麼映射區記憶體就也可以讀寫
- flag也可以設為SHM_RDONLY限定只讀訪問
shmdt
shmdt刪除由shmat建立的連接。
//成功返回0,失敗返回-1
int shmdt(const void *shmaddr);
shmctl
shmctl用於對共用記憶體的各種控制操作。
//成功返回0,失敗返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
cmd可使用的命令有三個:
- IPC_RMID:從系統中刪除共用記憶體,此時buf參數設為NULL即可
- IPC_STAT:通過buf返回共用記憶體對應的shmid_ds結構,一般用此命令獲取共用記憶體區大小
- IPC_SET:通過buf設置共用記憶體對應shmid_ds結構中的shm_perm.uid、shm_perm.gid和shm_perm.mode
3. 簡單的程式
代碼實現
common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define FTOK_FILE "/home/delphi/ftok.file"
#define FTOK_ID 1
#define SHM_RD_PERMISSION 0444
#define SHM_WR_PERMISSION 0222
#define SHM_RW_PERMISSION (SHM_RD_PERMISSION | SHM_WR_PERMISSION)
#endif
shmcreate.c
#include "common.h"
int main(int argc, char **argv)
{
int length = atoi(argv[1]);
int oflag = IPC_CREAT | SHM_RW_PERMISSION;
int shmid = shmget(ftok(FTOK_FILE, FTOK_ID), length, oflag);
if (shmid >= 0)
{
printf("shmget create success, shmid = %d\n", shmid);
}
return 0;
}
shmrmid.c
#include "common.h"
int main(int argc, char **argv)
{
int shmid = shmget(ftok(FTOK_FILE, FTOK_ID), 0, SHM_RW_PERMISSION);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
shmwrite.c
#include "common.h"
int main(int argc, char **argv)
{
int shmid;
unsigned char *shmadd;
struct shmid_ds buf;
int i;
shmid = shmget(ftok(FTOK_FILE, FTOK_ID), 0, SHM_RW_PERMISSION);
shmadd = shmat(shmid, NULL, 0);
shmctl(shmid, IPC_STAT, &buf);
for (i = 0; i < buf.shm_segsz; i++)
{
*shmadd++ = i % 256;
}
return 0;
}
shmread.c
#include "common.h"
int main(int argc, char **argv)
{
int shmid;
unsigned char *shmadd;
unsigned char v;
struct shmid_ds buf;
int error = 0;
int i;
shmid = shmget(ftok(FTOK_FILE, FTOK_ID), 0, SHM_RW_PERMISSION);
shmadd = shmat(shmid, NULL, 0);
shmctl(shmid, IPC_STAT, &buf);
for (i = 0; i < buf.shm_segsz; i++)
{
v = *shmadd++;
if (v != (i % 256))
{
printf("error: shmadd[%d] = %d\n", i, v);
error++;
}
}
if (error == 0)
{
printf("all of read is ok\n");
}
return 0;
}