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

相关推荐
w6100104662 分钟前
CKAD-2026-Secret
运维·k8s·ckad
无巧不成书02183 分钟前
基于WSL 2的Docker远程开发全栈实战指南
运维·docker·容器·docker desktop·wsl 2·vs code远程开发·容器化开发
一个天蝎座 白勺 程序猿6 分钟前
踩坑生产后整理:KingbaseES表空间管理、auto_createtblspcdir参数深度解析与运维最佳实践
运维·数据库·kingbasees
赵庆明老师7 分钟前
Linux Docker打包
linux·运维·docker
Eloudy9 分钟前
docker pull ubuntu:22.04 失败的解决记录
运维·docker·容器
Strange_Head14 分钟前
《Linux系统编程篇》Linux Socket 网络编程03(Linux 进程间通信(IPC))——基础篇
linux·网络·单片机
Strange_Head19 分钟前
《Linux系统网络协议》从 TCP 到 HTTP:理解 Web 通信的第一步——网络篇
linux·网络·网络协议
爱吃生蚝的于勒29 分钟前
【Linux】重中之重!TCP协议
linux·运维·服务器·网络·学习·tcp/ip
楼田莉子31 分钟前
Linux网络:TCP协议
linux·运维·服务器·网络·tcp/ip
qq_2351321733 分钟前
五金制造行业ERP系统多少钱?易呈erp五金行业版功能模块详解与成功案例分享
大数据·运维·人工智能·制造·智能制造