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中,这是很自然的,因为操作系统要想管理共享内存,必须先描述共享内存再组织共享内存,描述共享内存需要结构体

相关推荐
CHANG_THE_WORLD15 小时前
在 VS Code 中让终端显示简洁路径(告别冗长全路径)
linux
va学弟15 小时前
Java 网络通信编程(9):从 BIO 到 NIO
java·运维·服务器·网络
凡人叶枫15 小时前
Effective C++ 条款05:了解 C++ 默默编写并调用哪些函数
java·linux·开发语言·c++·effective c++·编程范式
HackTwoHub15 小时前
关于文件上传漏洞深度绕过利用教程,突破命令执行限制
运维·安全·web安全·网络安全·系统安全·安全架构
Web极客码15 小时前
如何用 Docker 容器与“看门狗”脚本安全驯服 OpenClaw
服务器·人工智能·ai编程
William.csj15 小时前
服务器——终端ssh可以连接进服务器,vscode连接不进去服务器的解决办法
服务器·vscode·ssh
星光不负赶路人!15 小时前
【工作记录】sqlserver数据库操作及迁移
服务器·数据库·sqlserver
ftf拿破仑15 小时前
嵌入式面试高频问题
linux·面试
女神下凡15 小时前
轻量应用服务器 与 云服务器ECS 区别
运维·服务器
实在智能RPA15 小时前
培训Agent如何根据岗位自动发放计划?——2026企业级智能自动化实战指南
运维·服务器·人工智能·ai·自动化