【在Linux世界中追寻伟大的One Piece】System V共享内存

devtools/2024/10/9 3:31:11/

目录

1 -> System V共享内存

1.1 -> 共享内存数据结构

1.2 -> 共享内存函数

1.2.1 -> shmget函数

1.2.2 -> shmot函数

1.2.3 -> shmdt函数

1.2.4 -> shmctl函数

 1.3 -> 实例代码

2 -> System V消息队列

3 -> System V信号量


1 -> System V共享内存

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

示意图:

1.1 -> 共享内存数据结构

struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */unsigned short shm_unused; /* compatibility */void* shm_unused2; /* ditto - used by DIPC */void* shm_unused3; /* unused */
};

1.2 -> 共享内存函数

1.2.1 -> shmget函数

功能:用来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

1.2.2 -> shmot函数

功能:将共享内存段连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

说明:

shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr -
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

1.2.3 -> shmdt函数

功能:将共享内存段与当前进程脱离
原型
int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

1.2.4 -> shmctl函数

功能:用于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
命令说明
IPC_STAT把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID删除共享内存段

 1.3 -> 实例代码

测试代码结构

# ls
client.c comm.c comm.h Makefile server.c
# cat Makefile
.PHONY:all
all:server client
client:client.c comm.c
gcc -o $@ $^
server:server.c comm.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f client server

comm.h

#ifndef COMM_H
#define COMM_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
int createShm(int size);
int destroyShm(int shmid);
int getShm(int size);
#endif

comm.c

#include "comm.h"static int commShm(int size, int flags)
{key_t _key = ftok(PATHNAME, PROJ_ID);if (_key < 0) {perror("ftok");return -1;}int shmid = 0;if ((shmid = shmget(_key, size, flags)) < 0) {perror("shmget");return -2;}return shmid;
}int destroyShm(int shmid)
{if (shmctl(shmid, IPC_RMID, NULL) < 0) {perror("shmctl");return -1;}return 0;
}int createShm(int size)
{return commShm(size, IPC_CREAT | IPC_EXCL | 0666);
}int getShm(int size)
{return commShm(size, IPC_CREAT);
}

server.c

#include "comm.h"int main()
{int shmid = createShm(4096);char* addr = shmat(shmid, NULL, 0);sleep(2);int i = 0;while (i++ < 26) {printf("client# %s\n", addr);sleep(1);}shmdt(addr);sleep(2);destroyShm(shmid);return 0;
}

client.c

#include "comm.h"int main()
{int shmid = getShm(4096);sleep(1);char* addr = shmat(shmid, NULL, 0);sleep(2);int i = 0;while (i < 26) {addr[i] = 'A' + i;i++;addr[i] = 0;sleep(1);}shmdt(addr);sleep(2);return 0;
}

ctrl+c终止进程,再次重启。

2 -> System V消息队列

System V消息队列是一种进程间通信(IPC)机制,它允许进程通过消息的形式进行数据交换。消息队列由内核管理,可以存储多种类型的消息,并且支持消息的有序存取。每个消息都有一个类型字段,接收进程可以根据消息类型来接收特定的消息。

消息队列的关键数据结构

消息队列的状态和配置信息存储在struct msqid_ds数据结构中,它包含了队列的权限、消息计数、最大消息大小、队列字节数、最近操作进程的PID等信息。

消息队列的创建与操作

  • 创建或打开消息队列使用msgget函数,该函数接受一个键值(key)和标志(msgflg)作为参数。如果消息队列不存在且msgflg包含IPC_CREAT标志,则会创建一个新的消息队列。
  • 向消息队列发送消息使用msgsnd函数,接收消息使用msgrcv函数。这些函数允许进程指定消息的类型和大小,以及接收消息时的行为(例如阻塞或非阻塞)。
  • 控制消息队列的状态,如删除消息队列或获取消息队列的统计信息,使用msgctl函数。

消息队列的编程示例

在编程实践中,可以通过创建发送进程和接收进程来演示消息队列的使用。发送进程将数据封装成消息并发送到队列,接收进程则从队列中取出消息进行处理。这种模式适用于生产者-消费者场景,其中一个或多个进程产生数据(生产者),另一个或多个进程消费数据(消费者)。

消息队列的实际应用

消息队列不仅限于简单的数据传递,它们还可以用于更复杂的通信模式,如实现信号量或实现更高级的同步机制。在多进程或多线程的应用程序中,消息队列提供了一种灵活且高效的通信手段。

3 -> System V信号量

System V信号量是一种进程间同步机制,它允许多个进程通过对共享资源的访问计数来进行协调。信号量可以是二元的(用于互斥),也可以是非负整数(用于资源计数)。System V信号量由内核管理,并通过一系列系统调用来创建、操作和销毁。

System V信号量的关键数据结构

System V信号量的核心数据结构是semid_ds,它包含了信号量集的权限、信号量的值、信号量的状态信息等。每个信号量集中的信号量由sem结构表示,其中包含信号量的当前值和相关的进程计数信息。

System V信号量的创建与操作

创建信号量集使用semget函数,该函数接受一个键值(key)、信号量的数量(nsems)和标志(semflg)作为参数。操作信号量集使用semop函数,该函数接受信号量集的标识符、指向sembuf结构数组的指针以及操作的数量作为参数。sembuf结构定义了对信号量执行的具体操作,如等待(P)或信号(V)操作。

System V信号量的编程示例

在编程中,可以通过定义信号量集、初始化信号量值、执行P和V操作以及最终销毁信号量集来实现进程间同步。例如,一个生产者-消费者问题可以通过信号量来确保生产者不会超过消费者的消费速度,防止缓冲区溢出。

System V信号量的实际应用

System V信号量广泛应用于操作系统中,用于实现进程间的同步和互斥。它们可以用于控制对共享资源的访问,管理进程的执行顺序,以及实现更复杂的同步算法。


感谢各位大佬支持!!!

互三啦!!!


http://www.ppmy.cn/devtools/120426.html

相关文章

【MySQL基础刷题】总结题型(一)

一篇十题复习的负担小一点 不重要的知识点1.第二高的薪水2.分数排名3.连续出现的数字3.部门工资最高的员工4.部门工资前三高的人5.游戏玩法分析II6.游戏玩法分析III7.购买了A和B但没有购买C8.机器的进程平均运行时间9.每位学生的最高成绩10.学生们参加各科测试的次数 不重要的知…

图像处理基础知识点简记

简单记录一下图像处理的基础知识点 一、取样 1、释义 图像的取样就是图像在空间上的离散化处理,即使空间上连续变化的图像离散化, 决定了图像的空间分辨率。 2、过程 简单描述一下图象取样的基本过程,首先用一个网格把待处理的图像覆盖,然后把每一小格上模拟图像的各个…

VB.NET中如何利用LINQ to SQL进行数据库操作

在VB.NET中&#xff0c;利用LINQ to SQL进行数据库操作是一种强大的方式&#xff0c;它允许你使用VB.NET的查询语法来直接操作数据库&#xff0c;而无需编写大量的SQL代码。LINQ to SQL是一种ORM&#xff08;对象关系映射&#xff09;技术&#xff0c;它将数据库表映射为.NET中…

若无向图G(V,E)中含7个顶点,为保证图G在任何情况下都是连通的,则需要的边数最少是多少?

这乍一看是不是可抽象&#xff08;迷糊&#xff09;了&#xff0c;butttt待我小翻译一下。 先举少一点的例子&#xff0c;假如我们有三个点&#xff0c;我给你两条边&#xff0c;那是不是不管咋连都一定一定是连通的。 那我们再进一步&#xff0c;假如四个点呢&#xff1f;我给…

【STM32】 TCP/IP通信协议(1)--LwIP介绍

一、前言 TCP/IP是干啥的&#xff1f;它跟SPI、IIC、CAN有什么区别&#xff1f;它如何实现stm32的通讯&#xff1f;如何去配置&#xff1f;为了搞懂这些问题&#xff0c;查询资料可解决如下疑问&#xff1a; 1.为什么要用以太网通信? 以太网(Ethernet) 是指遵守 IEEE 802.3 …

操作符详解与表达式求值

目录 操作符分类 1.算数操作符 2.移位操作符&#xff08;只适用于整数范围&#xff09; &#xff08;1&#xff09;引入 &#xff08;2&#xff09;左移操作符<< &#xff08;2&#xff09;右移操作符>> 3.位操作符 4.赋值操作符 复合赋值符 5.单目操作符 5…

【系统架构设计师】专题:需求工程总结

更多内容请见: 备考系统架构设计师-核心总结目录 文章目录 一、软件需求二、需求获取三、需求分析3.1 需求分析的任务3.2 结构化的需求分析四、需求定义五、需求验证六、需求管理一、软件需求 软件需求是指 用户对系统在功能、行为、性能、设计约束等方面的期望。是指用户解决…

CSS点击事件穿透

假设盒子中有一个按钮&#xff0c;要实现点击按钮时透过按钮的点击事件&#xff0c;只触发盒子的点击事件&#xff0c;这个时候只需要给按钮设置如下属性即可&#xff1a; button {/* 清除点击事件 */pointer-events: none; } uniapp测试代码如下&#xff1a; <templat…