OS53.【Linux】System V 共享内存(2)

🧨🧨🧨🧨🧨🧨🧨🧨🧨除夕篇🧨🧨🧨🧨🧨🧨🧨🧨🧨

🎉❤️🎉❤️🎉❤️🎉❤️🎉❤️祝各位程序员们马年大吉 万事如意!❤️🎉❤️🎉❤️🎉❤️🎉❤️🎉

目录

1.知识回顾

[2.接着System V 共享内存(1)继续讲](#2.接着System V 共享内存(1)继续讲)

通信代码

分析细节

结论

共享内存的特点

使用管道为共享内存添加同步机制

共享内存的属性


1.知识回顾

参见OS52.【Linux】System V 共享内存(1)文章复习共享内存的基础知识

2.接着System V 共享内存(1)继续讲

通信代码

上篇文章的最后实现了让两个进程使用共享内存进行通信

shm1.cpp写入:

cpp 复制代码
#include <stdio.h>
#include <iostream>
#include "header.hpp"
int main() 
{
    //为了减小代码行数,系统调用的错误执行结果都没有判断
    int shmid=get_new_shared_memory(); 
    char* start_addr=(char*)shmat(shmid,nullptr,0);
    for (;;) 
    {
        sleep(1);
        std::cout<<start_addr;
        fflush(stdout);
    }
    shmdt(start_addr);
    shmctl(shmid,IPC_RMID,nullptr);
    return 0;
}

shm2.cpp写入:

cpp 复制代码
#include <stdio.h>
#include <iostream>
#include "header.hpp"
int main() 
{
    //为了减小代码行数,系统调用的错误执行结果都没有判断  
    int shmid=get_old_shared_memory(); 
    char* start_addr=(char*)shmat(shmid,nullptr,0);
    for (;;)
    {
        std::cin>>start_addr;
    }
    shmdt(start_addr);
    return 0;
}

运行结果:

分析细节

注意到:

cpp 复制代码
for (;;)
{
    std::cin>>start_addr;
}

没有将输入暂存到缓冲区,然后将缓冲区数据拷贝到start_addr处

结论

结论: 1.一旦有了共享内存,可以将其挂接到进程自己的地址空间中,进程可以直接把他当成自己的内存空间来使用

2. 一旦有数据写入到共享内存,进程就能立马看到, 不需要经过系统调用

共享内存的特点

从以上结论可以得出共享内存的特点: 共享内存没有同步互斥值之类的保护机制

对比管道,管道中如果没有数据,那么进程读管道会被阻塞

其次,共享内存是所有的进程间通信中最快的,因为不需要经过系统调用

再之,共享内存内部的数据,由用户自己维护

使用管道为共享内存添加同步机制

共享内存无同步机制,可以借助管道

管道的复习:
OS43.【Linux】进程间通信 管道通信理论部分

OS44.【Linux】进程间通信 管道通信代码部分(1)

OS45.【Linux】进程间通信 管道通信代码部分(2)

OS46.【Linux】进程间通信 管道的应用场景和进程池项目

例如: shm2.out向共享内存写入数据,shm1.out读数据,可以为共享内存配上管道来保证同步

1.读写端正常,管道为空,读端阻塞,此时不能读共享内存数据

2.读写端正常,管道不为空,读端不阻塞,此时能读共享内存数据

header.cpp写入:

cpp 复制代码
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#define SIZE 1024
#define PROJ_ID 0x1344 
key_t get_key()
{
    char buffer[SIZE];
    char* pathname=getcwd(buffer,sizeof(buffer));
    if (pathname==nullptr)
    {
        perror("getcwd failed");
        exit(1);
    }
    return ftok(pathname,PROJ_ID);
}

int get_new_shared_memory()
{
    key_t key=get_key();
    //申请新的共享内存
    int shmid=shmget(key,4097,IPC_CREAT|IPC_EXCL|0666);
    return shmid;
}

int get_old_shared_memory()
{
    key_t key=get_key();
    //申请新的共享内存
    int shmid=shmget(key,4097,IPC_CREAT|0666);
    return shmid;
}

shm1.cpp写入:

cpp 复制代码
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "header.hpp"
int main() 
{ 
    //为了减小代码行数,系统调用的错误执行结果都没有判断
    int shmid=get_new_shared_memory();  
    char* start_addr=(char*)shmat(shmid,nullptr,0);
    mkfifo("./tmp_fifo",0664);
    int fd=open("./tmp_fifo",O_RDONLY);

    for (;;) 
    {
        char ch;
        ssize_t n=read(fd,&ch,1);
        if (n==0||n<0)
            break;
        std::cout<<start_addr<<std::endl;
    }
    shmdt(start_addr);
    shmctl(shmid,IPC_RMID,nullptr);
    unlink("./tmp_fifo");
    return 0;
}

shm2.cpp写入:

cpp 复制代码
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "header.hpp" 
int main()  
{
    //为了减小代码行数,系统调用的错误执行结果都没有判断  
    int shmid=get_old_shared_memory(); 
    char* start_addr=(char*)shmat(shmid,nullptr,0);
    int fd=open("./tmp_fifo",O_WRONLY);
    
    for (;;)
    {
        std::cin>>start_addr;
        write(fd,"",1);
    }
    shmdt(start_addr);
    return 0;
}

运行结果:

我这个共享内存+管道代码最初版本写的有问题,下篇文章讲讲排错记录

共享内存的属性

man手册是这样说的:共享内存的属性存储在struct shmid_ds

cpp 复制代码
struct shmid_ds {
    struct ipc_perm shm_perm;    /* Ownership and permissions */
    size_t          shm_segsz;   /* Size of segment (bytes) */
    time_t          shm_atime;   /* Last attach time */
    time_t          shm_dtime;   /* Last detach time */
    time_t          shm_ctime;   /* Creation time/time of last
                                    modification via shmctl() */
    pid_t           shm_cpid;    /* PID of creator */
    pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
    shmatt_t        shm_nattch;  /* No. of current attaches */
    ...
};
 
struct ipc_perm {
        key_t          __key;    /* Key supplied to shmget(2) */
        uid_t          uid;      /* Effective UID of owner */
        gid_t          gid;      /* Effective GID of owner */
        uid_t          cuid;     /* Effective UID of creator */
        gid_t          cgid;     /* Effective GID of creator */
        unsigned short mode;     /* Permissions + SHM_DEST and
                                    SHM_LOCKED flags */
        unsigned short __seq;    /* Sequence number */
    };

注: struct shmid_ds内含struct ipc_perm,结构体嵌套

对于一个已经创建好的共享内存,其key存储在struct ipc_perm中,这是很自然的,因为操作系统要想管理共享内存,必须先描述共享内存再组织共享内存,描述共享内存需要结构体

相关推荐
REDcker3 小时前
DNS技术详解
服务器·后端·计算机网络·互联网·dns·服务端
上海合宙LuatOS3 小时前
LuatOS核心库API——【io】 io操作(扩展)
java·服务器·前端·网络·单片机·嵌入式硬件·物联网
能源革命5 小时前
Ubuntu_24.04 安装OpenClaw教程
linux·ubuntu
志栋智能6 小时前
AI驱动的安全自动化机器人:从“告警疲劳”到“智能免疫”的防御革命
运维·人工智能·安全·机器人·自动化
laocui16 小时前
树莓派Ubuntu系统安装openclow(豆包+QQ机器人)
linux·运维·ubuntu
qq_24218863327 小时前
快速搭建跨环境检测服务的步骤
linux·开发语言·windows·python·macos
志栋智能7 小时前
自动化运维真的只能选复杂平台吗?
运维·网络·数据库·人工智能·自动化
月明长歌7 小时前
Java 网络编程套接字入门:从“发一段数据”到“写一个可并发的服务器”
java·服务器·网络
冗量7 小时前
《性能之巅》第七章:内存 读书笔记
服务器·性能优化·性能调优