IO进程——共享内存

目录

1.共享内存

1.1概念

1.2特点

1.3步骤

1.4函数接口

1.4.1创建key值

1.4.2创建共享内存

1.4.3映射共享内存

1.4.4取消映射

1.4.5删除共享

1.5操作指令


1.共享内存

1.1概念

共享内存指的是操作系统在物理内存中申请的一块空间,应用程序可以映射到这块空间,进行直接读写操作

1.2特点

1.共享内存是一种最为高效的进程通信方式,进程可以直接读写内存,而不需要任何数据的拷贝

2.为了在多个进程间交换信息,内核专门流出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间

3.进程可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高效率

4.由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量

1.3步骤

1.创建唯一key值,ftok

2.创建或打开共享内存

3.映射共享内存

4.取消映射

5.删除共享内存

1.4函数接口

1.4.1创建key值

#include <sys/types.h>

#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);

功能:创建key值

参数:

        pathname:文件名

        proj_id:取整型数的低8位数值

返回值:

        成功:key值

        失败:-1

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>

int main(int argc, char const *argv[])
{
    key_t key;
    key = fork("./app",'a');
    if (key < 0)
    {
        perror("fork err");
        return -1;
    }
    printf("%#x\n",key);
    return 0;
}

补充:

        key值是由pathname的inode号和proj_id的低8位组合而成的,这样形成的唯一标识符用于在进程间通信中标识消息队列、信号量或共享内存等系统资源。

        在进程间通信(IPC)中,系统需要一种方法来唯一地标识一个资源,例如消息队列、信号量或共享内存。为此,系统V IPC使用了键值(key),它通过ftok函数生成。这个键值是基于指定的文件(由pathname给出)的索引节点号(inode number)和项目标识符(proj_id)的低8位组合而成。

        从结构上来看,ftok函数接受两个参数:一个是文件名(pathname),另一个是项目标识符(proj_id)。该函数利用这两个参数生成一个键值,这个值是唯一的,并且可以被用来识别某个特定的IPC资源。具体来说,ftok函数会提取pathname参数所指定的文件的索引节点信息,并将这个信息与proj_id参数的低8位组合起来,形成一个32位的键值。

        综上所述,键值的生成不仅依赖于文件系统的索引节点号,还依赖于proj_id的低8位。这意味着同一个文件可以产生多达256个不同的键值(从0x01到0xFF),为不同的IPC资源提供唯一性。这种设计使得在同一个项目中可以创建多个不同的IPC资源,而不会因为键值冲突导致无法区分。

1.4.2创建共享内存

int shmget ( key_t key , size_t size , int shmflg );

功能:创建或打开共享内存

参数:

        key 键值

        size 共享内存的大小

                          创建         检测错误

        shmflg IPC_CREAT|IPC_EXCL|0777 创建共享内存的时候的权限

返回值:

        成功   shmid   共享内存的id

        出错 -1

查看创建的共享内存的命令:ipcs -m

示例:

int shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 06666);
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            printf("文件已存在\n");
            shmid = shmget(key, 64, 0666);
        }
        else
        {
            perror("shmget err");
            return -1;
        }
    }

1.4.3映射共享内存

void * shmat ( int shmid , const void * shmaddr , int shmflg );

功能:映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

参数:

        shmid 共享内存的id号

        shmaddr 一般为NULL,表示由系统自动完成映射

                        如果不为NULL,那么有用户指定

        shmflg:SHM_RDONLY就是对该共享内存只进行读操作

                                        0 可读可写

返回值:

        成功:完成映射后的地址,

        出错:(void *)-1的地址

示例:

//映射
    char *p = shmat(shmid, NULL, 0);//此处的0为可读可写
    if (p == (void *) - 1)
    {
        perror("shat err");
        return -1;
    }
    //向共享内中存放数据
    scanf("%s",p);
    printf("%s\n",p);
    return 0;

1.4.4取消映射

int shmdt ( const void * shmaddr );

功能:取消映射

参数:要取消的地址

返回值:

        成功0

        失败的-1

//取消映射
shmat(p);
getchar();

1.4.5删除共享

int shmctl ( int shmid , int cmd , struct shmid_ds * buf );

功能:(删除共享内存),对共享内存进行各种操作

参数:

        shmid 共享内存的id号

        cmd IPC_STAT 获得shmid属性信息,存放在第三参数

        IPC_SET 设置shmid属性信息,要设置的属性放在第三参数

        IPC_RMID:删除共享内存,此时第三个参数为NULL即可

        struct shmid_ds *buf:是一个结构体指针,但我们是删除共享内存,所以并没有意义,我们直接设置为NULL就可以了

返回:

        成功0

        失败-1

示例:

shmctl(shmid, IPC_RMID, NULL);

1.5操作指令

ipcs    -m:查看系统中创建的共享内存

ipcrm     -m [shmid]:删除创建的共享内存

练习:

        通过共享内存实现进程间通信,一个进程从终端输入数据,另一个进程打印数据,循环执行,当输入quit时循环结束

 输入数据函数

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

struct data
{
    int flag; // 标志位,用于判断数据是否已写入共享内存
    char buf[32]; // 存储输入的字符串
};

int main(int argc, char const *argv[])
{
    key_t key; // 定义一个key_t类型的变量,用于存储生成的键值
    key = ftok("./app", 'a'); // 使用ftok函数生成一个键值,参数为文件路径和字符
    struct data *p = NULL; // 定义一个指向data结构体的指针
    int shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666); // 创建共享内存,大小为64字节

    if (key < 0) // 如果生成键值失败
    {
        perror("ftok err"); // 输出错误信息
        return -1; // 返回错误代码
    }
    if (shmid <= 0) // 如果共享内存创建失败
    {
        if (errno == EEXIST) // 如果错误原因是共享内存已存在
        {
            printf("file exits"); // 输出提示信息
            shmid = shmget(key, 64, 066); // 重新获取共享内存的ID
        }
        else // 如果错误原因不是共享内存已存在
        {
            perror("shmid err"); // 输出错误信息
            return -1; // 返回错误代码
        }
    }
    // 映射共享内存到当前进程的地址空间
    p = shmat(shmid, NULL, 0);
    if (p == (void *)-1) // 如果映射失败
    {
        perror("shat err"); // 输出错误信息
    }
    p->flag = 0; // 初始化标志位为0
    while (1) // 无限循环
    {
        if (p->flag == 0) // 如果标志位为0,表示共享内存中的数据未被修改
        {
            scanf("%s", p->buf); // 从标准输入读取字符串并存入共享内存
            p->flag = 1; // 将标志位设为1,表示数据已被修改
            if (!strcmp(p->buf, "quit")) // 如果输入的字符串为"quit"
                break; // 跳出循环
        }
    }
    // 取消映射共享内存
    shmdt(p);
    return 0; // 程序正常结束
}

输出数据函数 

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

struct data
{
    int flag; // 标志位,用于判断数据是否已写入共享内存
    char buf[32]; // 存储输入的字符串
};

int main(int argc, char const *argv[])
{
    key_t key; // 定义一个key_t类型的变量,用于存储生成的键值
    key = ftok("./app", 'a'); // 使用ftok函数生成一个键值,参数为文件路径和字符
    struct data *p = NULL; // 定义一个指向data结构体的指针
    int shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666); // 创建共享内存,大小为64字节

    if (key < 0) // 如果生成键值失败
    {
        perror("ftok err"); // 输出错误信息
        return -1; // 返回错误代码
    }
    if (shmid <= 0) // 如果共享内存创建失败
    {
        if (errno == EEXIST) // 如果错误原因是共享内存已存在
        {
            printf("file exits"); // 输出提示信息
            shmid = shmget(key, 64, 066); // 重新获取共享内存的ID
        }
        else // 如果错误原因不是共享内存已存在
        {
            perror("shmid err"); // 输出错误信息
            return -1; // 返回错误代码
        }
    }
    // 映射共享内存到当前进程的地址空间
    p = shmat(shmid, NULL, 0);
    if (p == (void *)-1) // 如果映射失败
    {
        perror("shat err"); // 输出错误信息
    }
    p->flag = 0; // 初始化标志位为0
    while (1) // 无限循环
    {
        if (p->flag == 1) // 如果标志位为1,表示共享内存中的数据已被修改
        {
            if (!strcmp(p->buf, "quit")) // 如果输入的字符串为"quit"
                break; // 跳出循环
            printf("p:%s", p->buf); // 输出共享内存中的字符串
            p->flag = 1; // 将标志位设为1,表示数据已被修改
        }
    }
    // 取消映射共享内存
    shmdt(p);
    return 0; // 程序正常结束
}
  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值