【Linux】进程间通信之共享内存(下)

简介: 【Linux】进程间通信之共享内存(下)

下面我们将代码运行起来测试一下:

22666ce1c4b44844b233a167f36444c9.png71f7a0af3448453cafe9f6c890b2e700.png


我们将程序运行起来发现并没有问题,下面我们查看共享内存是否创建成功,ipcs这个命令可以显示出三条资源:

d12f94b447334b4883853acb0c0d9d3c.png

第一条资源为消息队列,第二条资源为共享内存段,第三个为共享内存核心数组,我们主要看第二条,可以看到我们创建的1024大小的共享内存创建成功了。当然我们可以只查第二条,命令是ipcs -m :

0cf9fceb6dd042cdad79fc8173ee3ea7.png

下面我们讲一下上面所代表的意思,key就像文件的inode一样,而shmid就像文件的fd一样shmid才是操作共享内存所需要的核心数据。owner是谁创建的,perms是权限,nattch是与这个共享内存的连接数。下面我们在讲一下删除一个共享内存的命令:ipcrm -m +shmid(刚刚讲过shmid是用来操作共享内存的,与文件的fd作用一样):

fea89b013daf48dc8350c35e91aaa804.png


我们成功的删除了刚刚创建的共享内存。我们接着代码往下写,创建了共享内存后可以让客户端往服务端写一些东西,然后退出的时候需要删除共享内存,我们先来看看如何删除共享内存:


6cf9ba670d6d4976ac90f9f1c2b7382c.png

利用系统调用删除共享内存需要shmctl函数,第一个参数就是共享内存的shmid,第二个参数是指令,也就是说对共享内存做什么操作,我们看看指令有哪些:

54320a79571b40c88b37acade72fcf49.png

常见的指令有这么几个,而IPC_RMID就是真正删除共享内存的操作,第一个IPC_STAT是获取共享内存的属性,而第三个参数是一个共享内存的结构体的指针可以查看共享内存对应的属性:

f3048b36cd304cfcb8a2f462cdb6ac26.png


下面我们就写一个删除共享内存函数:

void delshm(int shmid)
{
    int n = shmctl(shmid,IPC_RMID,nullptr);
    assert(n!=-1);
    (void)n;
}



因为我们删除共享内存的时候不关心它的属性,所以我们直接设为空即可。

a96c0bc32e0645899501cfb28937715a.png

下面我们给大家演示一下查看共享内存的属性:

f881024ce4a54382bcb7e5f03503cab5.pngfecc2836a9974f91a988c559050d39c3.png


下面我们可以在创建共享内存的时候将权限也设置好:

int creatShm(key_t k,int size)
{
    umask(0);
    return createShmHelper(k,size,IPC_CREAT|IPC_EXCL|0666);
}

下面我们要将创建出来的共享内存与进程关联起来,要关联得需要shmat函数:

fcd58f993b9e4031a9292ead4926d2fd.png


第一个参数我们都知道,第二个参数的意思是可以指定将共享内存挂接到指定的地址处(在这里可以设为nullptr,nullptr后操作系统会自己选择合适的地址挂接),第三个参数是设置共享内存是只读的还是什么其他的权限(我们可以设为0,设为0默认是可读可写)

char* attachShm(int shmid)
{
    char* start = (char*)shmat(shmid,nullptr,0);
    return start;
}


4ab9f95c02ed487f979ec36f03d17e95.pngf873ed45566842c4841cc1678166e2de.png


当我们将进程和共享内存关联后,下一步就是退出前将他们去关联,去关联同样也需要函数,这个函数是shmdt:

ce17f85f1cab4b009dfc8ce35f42190e.png

这个函数的参数我们已经讲过了,就是刚刚关联时候给我们返回的那个地址,所以我们可以直接写代码了:

void detachShm(char* start)
{
    int n = shmdt(start);
    assert(n!=-1);
    (void)n;
}


32b0a1a194b249f58cb2c7707c341e48.pngcfe02bf9a9964f2f8e44e18ad3da95d1.png


以上内存的所有点我们就讲完了,下面我们通过一个类封装一下让客户端和服务端的代码可以少一些:

#define SERVER 1
#define CLIENT 0
class Init
{
public:
    Init(int type)
    {
        key_t k = getKey();
        if (type==SERVER)
        {
            shmid = creatShm(k,gsize);
        }
        else 
        {
            shmid = getShm(k,gsize);
        }
        start = attachShm(shmid);
    }
    char* getStart()
    {
        return start;
    }
    ~Init()
    {
        detachShm(start);
        if (type==SERVER)
        {
            delShm(shmid);
        }
    }
private:
    char* start;
    int type;
    int shmid;
}


通过以上类的封装,我们的客户端和服务端就能简化为以下这样:

1d9b3b51f466491cb82d8746542c6b89.pnge4461a60fd354872a4b29cfadd7f35d5.pngf3238f4350fe403bbffafc5615dbb37a.png1b8ab36015514316a6e03014c8a6d6bd.pngf9fb260e1cce4ff08ec0ab54c5b5517c.png

我们可以看到当我们一开始两个端口都运行的时候有两个进程链接在共享内存上,当客户端指令输入完成退出后就只剩下服务端,当服务端也退出后那么连接数就为0了。

以上就是我们共享内存的所有内容,学了共享内存要知道共享内存是进程间通信的几种方式中访问速度最快的。


总结



使用ipcrm -m 命令删除指定共享内存后,是不会直接释放共享内存的,因为共享内存的生命周期是随操作系统的,只有共享内存当前的映射链接数为0才会被删除释放。


使用ipcrm -a 可以删除所有进程间通信资源(a代表all也就是全部的意思)


ipcrm -m删除共享内存,-q删除消息队列,-s删除信号量


共享内存实现实现通信的原理是因为所有进程操作映射同一块物理内存。


共享内存的操作是非进程安全的,多个进程同时对共享内存读写是有可能造成数据的交叉写入或读取,造成数据混乱。


共享内存的删除操作并非是直接删除,而是拒绝后续映射,只有在当前映射链接数为0的时候表示没有进程访问了,才会真正的被删除。


共享内存生命周期随内核,只要不删除,就一直存在于内核中,除非重启系统或者手动删除。

目录
打赏
0
0
0
0
0
分享
相关文章
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件
本文详细介绍了Linux中的进程IO与系统调用,包括 `open`、`write`、`read`和 `close`函数及其用法,解释了文件描述符(fd)的概念,并深入探讨了Linux中的“一切皆文件”思想。这种设计极大地简化了系统编程,使得处理不同类型的IO设备变得更加一致和简单。通过本文的学习,您应该能够更好地理解和应用Linux中的进程IO操作,提高系统编程的效率和能力。
78 34
|
13天前
|
Linux:守护进程(进程组、会话和守护进程)
守护进程在 Linux 系统中扮演着重要角色,通过后台执行关键任务和服务,确保系统的稳定运行。理解进程组和会话的概念,是正确创建和管理守护进程的基础。使用现代的 `systemd` 或传统的 `init.d` 方法,可以有效地管理守护进程,提升系统的可靠性和可维护性。希望本文能帮助读者深入理解并掌握 Linux 守护进程的相关知识。
28 7
|
12天前
|
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
32 5
Linux 进程管理基础
Linux 进程是操作系统中运行程序的实例,彼此隔离以确保安全性和稳定性。常用命令查看和管理进程:`ps` 显示当前终端会话相关进程;`ps aux` 和 `ps -ef` 显示所有进程信息;`ps -u username` 查看特定用户进程;`ps -e | grep <进程名>` 查找特定进程;`ps -p <PID>` 查看指定 PID 的进程详情。终止进程可用 `kill <PID>` 或 `pkill <进程名>`,强制终止加 `-9` 选项。
20 3
|
18天前
|
Linux系统内存使用优化技巧
交换空间(Swap)的优化 禁用 Swap sudo swapoff -a 作用:这个命令会禁用系统中所有的 Swap 空间。swapoff 命令用于关闭 Swap 空间,-a 参数表示关闭 /etc/fstab 文件中配置的所有 Swap 空间。 使用场景:在高性能应用场景下,比如数据库服务器或高性能计算服务器,禁用 Swap 可以减少磁盘 I/O,提高系统性能。
34 3
|
18天前
|
Linux查看内存命令
1. free free命令是最常用的查看内存使用情况的命令。它显示系统的总内存、已使用内存、空闲内存和交换内存的总量。 free -h • -h 选项:以易读的格式(如GB、MB)显示内存大小。 输出示例: total used free shared buff/cache available Mem: 15Gi 4.7Gi 4.1Gi 288Mi 6.6Gi 9.9Gi Swap: 2.0Gi 0B 2.0Gi • to
31 2
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
68 16
|
3天前
|
Linux 常用文件查看命令
`cat` 命令用于连接文件并打印到标准输出,适用于快速查看和合并文本文件内容。常用示例包括:`cat file1.txt` 查看单个文件,`cat file1.txt file2.txt` 合并多个文件,`cat > filename` 创建新文件,`cat >> filename` 追加内容。`more` 和 `less` 命令用于分页查看文件,`tail` 命令则用于查看文件末尾内容,支持实时追踪日志更新,如 `tail -f file.log`。
22 5
Linux 常用文件查看命令
|
1月前
|
Linux系统之whereis命令的基本使用
Linux系统之whereis命令的基本使用
77 24
Linux系统之whereis命令的基本使用
目录
目录
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等