System V共享內存

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用於建立一個新的共享內存或打開一個已存在的共享內存。ui

//成功返回共享內存標識符,
int shmget(key_t key, size_t size, int oflag);
  • 參數size是共享內存區大小,其他兩個參數含義及用法和System V信號量同樣
  • 當實際操做爲建立新的共享內存時,該內存區size個字節均被初始化爲0
  • 當實際操做爲打開已有共享內存時,size可設爲0,oflag設爲須要的讀寫權限

shmat

shmat用於把shmget建立或打開的共享內存鏈接到調用進程的地址空間。3d

//成功返回映射區起始地址,失敗返回-1
void *shmat(int shmid, const void *shmaddr, int flag);
  • shmid是shmget返回的標識符
  • shmaddr推薦設爲NULL,表示由系統決定映射區起始地址
  • flag通常設爲0,由於只要調用進程具備共享內存的讀寫權限,那麼映射區內存就也能夠讀寫
  • flag也能夠設爲SHM_RDONLY限定只讀訪問

shmdt

shmdt刪除由shmat創建的鏈接。code

//成功返回0,失敗返回-1
int shmdt(const void *shmaddr);

shmctl

shmctl用於對共享內存的各類控制操做。blog

//成功返回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;
}

代碼測試

相關文章
相關標籤/搜索