跃升“神子”级别:八重神子腿法极致精炼秘籍

核心内容摘要

解锁“www污污污”的奇幻世界:一场前所未有的感官盛宴
黑桃tv官方版_2

探索“S8视频加密线隐藏款”:科技赋能隐私,安全触手可及

目录

共享内存的通信原理

共享内存的创建ftokshmgetIPC相关命令共享内存的生命周期

共享内存的去关联shmatshmdt

共享内存的释放shmctlshmctl(shmid, IPC_RMID, NULL);

共享内存的使用

共享内存的通信原理操作系统预先分配一块物理内存称为共享内存多个进程通过各自的页表将这段内存映射到自身的虚拟地址空间通常是共享区使得不同进程的虚拟地址最终指向同一块物理内存。

进程可以直接读写该内存区域进行数据交换从而实现高效通信但需配合同步机制保证数据一致性由于进程具有严格的独立性其直接分配的内存只能自己独享无法直接用于进程间通信。

为了解决这一矛盾共享内存必须由作为全局管理者的操作系统内核来提供。

进程通过系统调用请求操作系统执行以下核心步骤来间接使用共享内存创建/获取一块共享内存区域、将其关联映射到自身地址空间并使用、通信完成后去关联、最终由系统销毁该区域。

创建/获取申请内存进程请求操作系统创建一块新的共享内存或获取一块已存在的共享内存的标识符。

操作系统在物理内存中为其分配空间。

关联进程将这块共享内存映射到自己的进程地址空间通常是共享区操作系统建立进程页表到该物理内存的映射关系并返回映射后的虚拟首地址供进程访问。

使用进程通过得到的虚拟地址直接读写该内存区域进行进程间通信。

去关联通信完成后进程断开与该共享内存的映射关系去关联使其从本进程的地址空间中移除。

销毁释放当所有使用该共享内存的进程都完成去关联后操作系统最终释放该共享内存资源。

为了管理系统中可能存在的多块共享内存操作系统采用“先描述再组织”的方式用一个内核数据结构如struct shmid_ds来描述每一块共享内存的信息大小、权限、关联进程数等再通过链表等数据结构将这些描述对象组织起来实现统一高效的管理

共享内存的创建ftok组成部分名称与类型详细说明与作用函数原型key_t ftok(const char *pathname, int proj_id);将文件路径和项目ID转换为System V IPC机制消息队列、共享内存、信号量使用的键值(key)。

函数功能生成IPC键值根据给定的路径名和项目ID生成一个唯一的key_t类型的键值用于不同进程通过相同参数获取同一个IPC对象。

包含头文件#include sys/ipc.h#include sys/types.h使用ftok函数必须包含这两个头文件。

参数1const char *pathname路径名指向一个已存在且可访问的文件或目录的路径字符串。

•必须存在路径指向的文件必须存在且有访问权限。

•通常用法使用一个固定的、所有进程都能访问的文件如/tmp/myapp,/etc/passwd, 或项目特定文件。

•原理依据函数会使用该文件的st_dev设备号和st_inoi-node号信息。

参数2int proj_id项目ID用户指定的单字节整数值

•范围限制只有低8位有效

超出范围会被截断取低8位。

•用途允许在同一文件上生成多个不同的key值。

•常见值通常用ASCII字符表示如a、b或十六进制0x01等。

返回值key_t key成功返回生成的key_t类型的键值通常是32位整数。

失败返回(key_t)-1并设置errno指示错误原因•ENOENT路径名指向的文件不存在•EACCES对路径名指向的文件无搜索权限•ESTALE文件系统已卸载关键特性

确定性相同(pathname, proj_id)组合在任何进程、任何时间调用都产生相同的key值。

跨进程性不同进程使用相同参数即可获得相同key从而访问同一个IPC对象。

非唯一性风险如果文件被删除重建i-node号可能变化导致key值改变。

常见错误

文件不存在最常见错误确保路径文件存在且稳定。

权限不足进程对路径文件无访问权限。

项目ID溢出超出255的值会被截断可能导致意外冲突。

文件被删除重建i-node号改变新旧进程可能获得不同key。

共享内存的键值key是用户进程预先约定的一个标识符它的核心作用是让不同进程能够通过相同的key值找到或创建同一个共享内存对象。

key并非由操作系统保证全局唯一而是由应用程序自身确保其唯一性通常通过ftok()函数基于文件路径生成。

第一个进程使用shmget(key, size, IPC_CREAT)创建共享内存时系统会将此key与它关联起来后续其他进程只需使用相同的key调用shmget()即可获取该共享内存的访问句柄。

因此key在整个共享内存通信机制中扮演的是进程间“约定地址”的角色类似于文件系统中的路径名其唯一性和一致性由使用它的各进程共同维护操作系统无法预知哪些进程需要通信、何时通信。

若由系统自动分配key则进程仍需通过其他渠道如文件、环境变量或硬编码交换这个key这反而增加了耦合度和复杂性。

用户约定key通常通过ftok或预定义常量使得通信双方能以松耦合的方式独立连接到同一资源共享内存因此成为一种独立、通用、不依赖特定进程关系的通信机制shmget组成部分名称与类型详细说明与作用功能获取共享内存标识符根据key创建或获取一块共享内存返回一个内核标识符(shmid)用于后续操作shmat,shmdt,shmctl。

参数1key_t key键值用于唯一标识系统中共享内存对象。

•IPC_PRIVATE(

总是创建新的共享内存通常用于父子进程间。

•用户指定key通过ftok()函数生成或直接指定一个非零整数用于无亲缘关系进程间的约定。

参数2size_t size请求的共享内存大小字节。

•创建时指定新共享内存的最小尺寸系统可能会向上取整到页大小如4KB的整数倍。

•获取时如果只是获取已存在的共享内存size可以为0若指定了大小且小于已存在内存的大小可能会报错。

参数3int shmflg创建标志与权限标志的组合。

这是一个位掩码由两部分按位或(|)组成A. 行为控制标志•IPC_CREAT如果key对应的共享内存不存在则创建它。

如果存在则直接获取其shmid。

•IPC_EXCL与IPC_CREAT一同使用。

如果共享内存已存在则调用失败返回-1errno设为EEXIST。

这用于确保创建者拿到的是全新的内存。

B. 权限标志八进制• 例如0666表示所有用户属主、组员、其他人都可读写。

• 例如0644属主可读写组员和其他人只读。

• 权限位实际受系统umask值影响最终权限 shmflg ~umask。

返回值int shmid成功返回一个非负整数即共享内存标识符。

这是后续所有操作挂接、控制、去关联的句柄。

失败返回-1并设置全局变量errno指示错误原因如ENOENT-未找到,EACCES-权限不足,EEXIST-已存在,EINVAL-参数无效等。

申请共享内存时操作系统会直接按内存页通常4KB的整数倍进行物理内存分配然后让用户使用申请的那一部分这样设计较为简单。

所以建议申请4kb的整数倍减少浪费在共享内存通信机制中IPC键值key是用户层进程间约定的查找标识符它由应用程序通过预定义或ftok函数生成用于在不同进程中指向同一个共享内存对象共享内存标识符shmid是操作系统内核分配和管理共享内存的唯一标识它在系统范围内唯一进程通过shmget系统调用获得shmid后所有后续操作映射、控制、分离都基于此shmid进行。

shmid与“一切皆文件”的理念兼容性较差因为它是一个独立的整数句柄而不是通过文件系统路径访问key像是一个逻辑路径名但其实现机制独立于文件系统。

IPC相关命令# 查看所有IPC资源 ipcs # 查看特定类型的资源 ipcs -m # 共享内存 ipcs -q # 消息队列 ipcs -s # 信号量 # 详细查看 ipcs -a # 所有详细信息默认 ipcs -l # 显示系统限制 ipcs -p # 显示PID信息 ipcs -t # 显示时间信息 ipcs -c # 显示创建者/拥有者 ipcs -u # 显示摘要使用情况# 删除共享内存 ipcrm -m shmid # 按shmid删除 ipcrm -M key # 按key删除 # 删除消息队列 ipcrm -q msqid # 按msqid删除 ipcrm -Q key # 按key删除 # 删除信号量 ipcrm -s semid # 按semid删除 ipcrm -S key # 按key删除 # 删除所有用户拥有的IPC资源危险 ipcrm -a # 删除当前用户的所有IPC ipcrm -A # 删除所有用户的IPC需要root共享内存的生命周期共享内存的生命周期是随内核的用户不主动关闭共享内存会一直存在除非内核重启用户释放

共享内存的去关联shmat项目详细说明函数原型void *shmat(int shmid, const void *shmaddr, int shmflg)功能描述将共享内存段关联到调用进程的地址空间使进程能够访问共享内存包含头文件#include sys/types.h#include sys/shm.h参数1int shmid•由shmget()返回的共享内存标识符• 必须是已存在的有效共享内存ID• 用于指定要附加的共享内存段参数2const void *shmaddr• 期望的附加地址建议设为NULL•shmaddr NULL系统自动选择合适地址•shmaddr ! NULL尝试在指定地址附加需对齐• 通常设置为NULL让系统选择可避免地址冲突参数3int shmflg• 附加标志位按位或组合•SHM_RDONLY以只读方式关联•SHM_RND当shmaddr非NULL时将其向下取整到SHMLBA边界•0默认读写方式返回值成功返回关联后的共享内存段在共享区的起始地址void*类型失败返回(void*)-1并设置errno权限控制• 创建时通过shmget()的权限位控制如0666• 关联时可通过SHM_RDONLY限制为只读• 权限检查进程必须有相应的访问权限引用计数每次成功shmat()会增加shm_nattch计数每次shmdt()会减少计数当计数为0且已标记删除时内存被释放错误码EACCES权限不足EINVALshmid无效或shmaddr不对齐ENOMEM进程地址空间不足EMFILE进程附加的共享内存段过多ENOSPC超出系统限制

注意事项

关联后必须检查返回值是否为(void*)-

不同进程关联后在各自共享区的起始地址可能不同不应存储绝对指针

使用完毕后必须调用shmdt()分离

确保同步机制信号量等已就绪

考虑使用SHM_RDONLY提高安全性shmdt项目详细说明函数原型int shmdt(const void *shmaddr)功能描述将共享内存段从调用进程的地址空间中分离解除关联包含头文件#include sys/types.h#include sys/shm.h参数const void *shmaddr• 由shmat()返回的共享内存起始地址• 必须是有效的、已关联的共享内存地址• 不能是NULL或无效地址返回值成功返回0失败返回-1并设置errno引用计数变化shm_nattch--减少关联进程计数当计数为0且shm_perm.mode包含IPC_RMID标志时物理内存被释放错误码EINVALshmaddr不是已关联的共享内存地址**EFAULT**shmaddr指向无效地址罕见 |与shmat关系配对操作shmat- 关联建立映射shmdt- 分离解除映射

注意事项

分离后不能再使用该指针访问共享内存

分离不释放物理内存除非是最后一个进程且已标记删除

可以多次调用shmdt对同一地址多次调用返回EINVAL

指针变量本身不会被修改但指向的内存已无效进程退出进程正常或异常退出时系统自动执行shmdt操作但显式调用shmdt是良好编程习惯分离后的指针指针变量仍保留原值但指向无效内存建议分离后立即设为NULLshmdt(ptr); ptr NULL;

共享内存的释放shmctl项目详细说明函数原型int shmctl(int shmid, int cmd, struct shmid_ds *buf)功能描述对共享内存段进行控制操作包括查询状态、修改属性、删除等包含头文件#include sys/ipc.h#include sys/shm.h参数1int shmid• 共享内存标识符• 由shmget()返回的有效ID参数2int cmd• 控制命令指定要执行的操作• 主要分为三类查询、设置、控制参数3struct shmid_ds *buf• 数据缓冲区指针• 根据cmd不同可能是输入或输出• 某些cmd可设为NULL返回值成功根据cmd不同返回不同值失败返回-1并设置errno命令分类查询命令IPC_STAT, IPC_INFO, SHM_INFO, SHM_STAT设置命令IPC_SET控制命令IPC_RMID, SHM_LOCK, SHM_UNLOCK命令值功能buf参数用途返回值权限要求IPC_STAT2获取共享内存状态信息输出缓冲区接收状态信息0读权限IPC_SET1修改共享内存参数输入缓冲区提供新参数0属主或rootIPC_RMID0立即/延迟删除共享内存可设为NULL0属主或rootIPC_INFO3获取系统IPC信息输出struct shminfo索引值无SHM_INFO14获取系统共享内存信息输出struct shm_info索引值无SHM_STAT13获取共享内存状态通过索引输出struct shmid_dsshmid无SHM_LOCK11锁定共享内存到物理RAM可设为NULL0rootSHM_UNLOCK12解锁共享内存可设为NULL0rootshmctl(shmid, IPC_RMID, NULL);标记删除立即将共享内存标记为dest状态延迟释放如果nattch 0立即释放物理内存和内核结构如果nattch 0等待所有进程shmdt()分离后自动释放阻止新挂接标记后其他进程无法再shmat()挂接该内存// IPC_RMID 的典型使用模式 int main() { int shmid shmget(key, size, IPC_CREAT|

; // 立即标记删除推荐做法 shmctl(shmid, IPC_RMID, NULL); // 此时 //

已关联的进程可继续使用 //

新进程无法关联 //

所有进程分离后自动释放 void *ptr shmat(shmid, NULL,

; // ... 使用 ... shmdt(ptr); // 最后一个进程分离后内存释放 return 0; }

共享内存的使用processa.cc#include comm.hpp //读取 int main() { //创建与关联 int shmid CreateShm(); char* shmaddr (char*)shmat(shmid, nullptr,

; //创建管道 Init init; // 打开管道 int fd open(FIFO_FILE, O_RDONLY); if (fd

{ logObj(Fatal, error string: %s, error code: %d, strerror(errno), errno); exit(FIFO_OPEN_ERR); } //开始通信 struct shmid_ds shmds; char tmp; while(true) { int n read(fd, tmp,

;//看看是否被通知 if(n

break; cout client say shmaddr endl; sleep(

; shmctl(shmid, IPC_STAT, shmds); cout shm nattch: shmds.shm_nattch endl; cout shm size: shmds.shm_segsz endl; printf(shm key: 0x%x\n, shmds.shm_perm.__key); cout shm mode: shmds.shm_perm.mode endl; } //去关联与删除 shmdt(shmaddr); shmctl(shmid, IPC_RMID, nullptr); close(fd); return 0; }processb.cc#include comm.hpp //写入 int main() { //获取与关联 int shmid GetShm(); char* shmaddr (char*)shmat(shmid, nullptr,

; // 打开管道 int fd open(FIFO_FILE, O_WRONLY); if (fd

{ logObj(Fatal, error string: %s, error code: %d, strerror(errno), errno); exit(FIFO_OPEN_ERR); } //开始通信 while(true) { cout Please Enter; fgets(shmaddr, 4096, stdin); write(fd, c,

;//通知对方 } //去关联 shmdt(shmaddr); return 0; }1processa是读端processb是写端2processa创建并关联共享内存后进行读取操作processb获取并关联共享内存后进行写入操作3进程一旦拥有并关联共享内存后进程就能够直接将共享内存作为自己的内存空间来使用不需要通过系统调用。

所以一旦processb进行写入操作processa立马就能执行读取操作4显然使用共享内存进行通信是所有进程间通信方式中最快的因为它拷贝少通信方式数据拷贝次数内核/用户切换具体过程共享内存1次或0次1次建立映射

数据写入共享内存1次

其他进程直接读取0次拷贝管道4次2次读写各1次

用户缓冲区→内核管道缓冲区1次

内核→用户缓冲区1次总计2次拷贝/方向双向4次5当然共享内存的数据要由用户自己维护这是因为共享内存没有同步读端不会阻塞等待写端写入和互斥写端未完整写入完数据就被读端读取导致数据不一致问题机制6这里使用命名管道进行保护措施同步机制写端先通过共享内存进行完写入操作后再通过命名管道发送一个字符通知读端读端只有通过命名管道读取到字符后才通过共享内存进行读取操作

17-起草html-17-起草应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123