sys V 进程间通信之共享内存

note

1.使用shmget将在内核创建一个共享内存区

2.使用shmctl才可以删除内核创建的共享内存区

3.使用shmat给当前进程开辟与内核共享内存对应的内存区p,用户态对p的操作会作用到内核共享内存区

code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <time.h>
#include <sys/wait.h>

int shm_id = -1;    // 共享内存实例(内核实例),由父进程管理
const size_t shm_len = 1024;    // 共享内存字节数
struct mm { // 父子进程通信数据协议
    int flag;   /* 父进程写状态111 or 子进程读状态222*/
    char data[1020];
};

static void remove_shm(void) {
    int ret = -1;
    
    if (shm_id != -1) {
        fprintf(stdout, "now remove by shm_id\n");
        ret = shmctl(shm_id, IPC_RMID, NULL);
        if (ret == -1) {
            fprintf(stderr, "shmctl error,%s\n", strerror(errno));
        }
        shm_id = -1;
    }
}

int main(int argc, char** argv) {
    key_t key = 0;
    pid_t pid = 0;
    char *pathname = argv[0];
    int proj_id = 0x11; // 盐值
    struct mm* shm = NULL;

    key = ftok(pathname, proj_id); // key由当前程序名和盐值生成
    if (key == -1) {
        fprintf(stderr, "ftok error,%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    shm_id = shmget(key, shm_len, IPC_CREAT|666);
    if (shm_id == -1) {
        fprintf(stderr, "shmget error,%s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    // 把共享内存映射到当前父进程空间
    shm = shmat(shm_id, NULL, 0); // 0:可读可写
    if (shm == (void*)(-1)) {
        fprintf(stderr, "shmat error,%s\n", strerror(errno));
        remove_shm();
        exit(EXIT_FAILURE);
    }
    shm->flag = 111;    //父进程先初始化共享内存读写标志

    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fork error,%s\n", strerror(errno));
        shmdt(shm); // 父进程解除共享内存映射
        remove_shm();   // 父进程销毁共享内存(内核实例)
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程
        int i = 0;
        shm = shmat(shm_id, NULL, 0);   // 把共享内存映射到当前子进程空间
        if (shm == (void*)(-1)) {
            fprintf(stderr, "fork error,%s\n", strerror(errno));
            exit(EXIT_FAILURE);
        }
        for (i = 0; i < 10; i++) {
            if (shm->flag == 222) {
                fprintf(stdout, "shm.data:%s", shm->data);
                shm->flag = 111;
            }
            sleep(1);
        }
        shmdt(shm); // 子进程解除共享内存映射
        exit(EXIT_SUCCESS);
    }
    else if (pid > 0) { // 父进程
        int i = 0;
        for (i = 0; i < 10; i++) {
            if (shm->flag == 111) {
                memset(shm->data, 0, shm_len);
                time_t t;
                time(&t);
                sprintf(shm->data, "parent writed to shm,time is %s", ctime(&t));
                shm->flag = 222;
            }
            sleep(1);
        }
        wait(NULL); // 父进程等待子进程资源回收完成
        shmdt(shm); // 父进程解除共享内存映射
        remove_shm();   // 父进程删除共享内存实例(内核实例)
        exit(EXIT_SUCCESS);
    }

    return 0;
}

test

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值