【Linux之进程间通信】06.Linux进程通信 - 共享内存

 
【Linux之进程间通信】

项目代码获取:https://gitee.com/chenshao777/linux-processes.git
(麻烦点个免费的Star哦,您的Star就是我的写作动力!)

06.共享内存

共享内存是Linux进程间的通信方式之一

创建共享内存函数

int shmget(key_t key, size_t size, int shmflg);
参数含义
keyIPC_PRIVATE或ftok()函数获取
size共享内存大小
shmflg权限

返回值:
成功返回共享内存描述符
失败返回-1

需要包含头文件

#include <sys/ipc.h>
#include <sys/shm.h>

共享内存和管道一样
有的共享内存只能在亲缘关系的进程间通信
有的可以在任意进程间通信
这取决于第一个参数 key


1.共享内存的创建(用于亲缘关系进程间)
参数 key 赋值为IPC_PRIVATE,表示用于亲缘关系进程
示例代码:

int shm_id;
//创建共享内存(亲缘进程)
shm_id = shmget(IPC_PRIVATE, 100, 0777);
if(shm_id < 0){
    printf("共享内存创建失败\n");
}

查看共享内存段:
可以看到通过 ipcs -m 命令获取到当前共享内存段中有一行

0x00000000 32778      hc         777        100        0   

它的键值为 0x00000000,这表示它只能用于亲缘进程通信


2.共享内存的创建(任意进程间)

参数 key 值通过 ftok(const char *pathname, int proj_id) 函数获取
ftok(const char *pathname, int proj_id) 函数的第一个参数是文件路径,当前路径就可以,第二个参数是一个int类型的值,可实际上只有8位(1~127)
成功返回Key值,失败返回-1
示例代码:

int shm_id;
int key;
key = ftok(".", 1);
if(key < 0 ){
   printf("创建key失败\n");
   return -1;
}
shm_id = shmget(key, 100, IPC_CREAT | 0777);
if(shm_id < 0){
    printf("共享内存创建失败\n");
}

注意的是,shmget函数第一个参数要换为key变量,第三个参数要加上IPC_CREAT宏

shmget(key, 100, IPC_CREAT | 0777);

查看共享内存段:
发现这一行中,键值为0x01011451,代表此共享内存可以用于非亲缘关系的进程间通信

0x01011451 32802      hc         777        100        0  

key值 具体如何生成?
key 31-24 proj_id 低8位
key 23-16 pathname的st_dev属性的低8位
key 15-0 pathname的st_ino属性的低16位

32位组合而成一个int值,就是我们的ftok的返回值了


3.两个进程间通信(非亲缘进程)

实验步骤:

  1. 进程1定义SIGUSER1信号处理函数,创建打开共享内存
  2. 进程1写入自己进程PID到共享内存,然后睡眠
  3. 进程2定义SIGUSER2信号处理函数,创建打开共享内存
  4. 进程2读取共享内存,获取到进程1的PID,写入自己的PID并发出SIGUSER1信号
  5. 进程1执行SIGUSER1信号处理函数,直接返回,继续执行,获取到进程2的PID,接着等待键盘输入
  6. 键盘输入字符,回车后进程1将数据写入共享内存,并发出SIGUSER2信号,接着睡眠
  7. 进程2执行SIGUSER1信号处理函数,直接返回退出睡眠,继续执行,读取共享内存,发出SIGUSER1信号,接着睡眠
  8. 进程1执行SIGUSER1信号处理函数,直接返回,进入下一循环,等待键盘输入
  9. 依次循环

测试结果:
进程1端:

hc@hc-vm:~/Linux_ARM/git/linux-processes/05.共享内存$ ./3.1shm_shmat 
已获取PID, 53110
hello
hahah
nihaod 
de  d 
de d e 
de 777777

进程2端:

hc@hc-vm:~/Linux_ARM/git/linux-processes/05.共享内存$ ./3.2shm_shmat 
已获取PID, 53104
从共享内存读出数据:hello
从共享内存读出数据:hahah
从共享内存读出数据:nihaod 
从共享内存读出数据:de  d 
从共享内存读出数据:de d e 
从共享内存读出数据:de 777777

进程1代码:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void handler(int sig)
{
    return;  //使得退出pause()
}

/*
    创建共享内存
    向共享内存写
    另一个进程来读
*/
int main(int argc, char *argv[])
{
    signal(SIGUSR1, handler);
    int shmid;
    int key;
    char *buff;
    int other_pid;
    
    //1.创建共享内存
    key = ftok(".", 1);
    shmid = shmget(key, 128, IPC_CREAT | 0777);

    //2.将内核中的共享内存映射到用户空间,第二个参数NULL表示系统自动分配用户空间地址
    //第三个参数0表示可读写
    buff = (char*)shmat(shmid, NULL, 0);
    if(buff == NULL){
        printf("映射共享内存失败\n");
        return -2;
    }

    //3.第一次向共享内存中写入自己的进程ID
    sprintf(buff, "%d", getpid());

    pause();  //等待另一个进程返回它的PID

    other_pid = atoi(buff);
    printf("已获取PID, %d\n", other_pid);

    //4.循环向共享内存写入数据
    while (1)
    {
        //写入数据到到共享内存,实际上向用户空间写就可以
        fgets(buff, 128, stdin);
        //发出信号,另一个进程读取共享内存
        kill(other_pid, SIGUSR2);  
        pause();
    }
    return 0;
} 

进程2代码:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    return;  //使得退出pause()
}

/*
    从共享内存读
    另一个进程写
*/
int main(int argc, char *argv[])
{
    signal(SIGUSR2, handler);
    int shmid;
    int key;
    char *buff;
    int other_pid;

    //打开共享内存
    key = ftok(".", 1);
    shmid = shmget(key, 128, IPC_CREAT | 0777);

    //将内核中的共享内存映射到用户空间,第二个参数NULL表示系统自动分配用户空间地址
    //第三个参数0表示可读写
    buff = (char*)shmat(shmid, NULL, 0);
    if(buff == NULL){
        printf("映射共享内存失败\n");
        return -2;
    }

    //第一次从共享内存中读数据,读取到的是另一个进程的PID
    other_pid = atoi(buff);
    printf("已获取PID, %d\n", other_pid);

    //向共享内存中写入自己的进程ID
    sprintf(buff, "%d", getpid());
    //发出信号
    kill(other_pid, SIGUSR1);


    while(1)
    {
        //睡眠,等待另一个进程发送SIGUSER2信号
        pause();
        printf("从共享内存读出数据:%s",buff);
        //发出信号
        kill(other_pid, SIGUSR1);
    }

    return 0;
} 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值