网站建设的书籍,网站上文章加入音乐是怎么做的,四川人力资源考试官网二建,下载免费软件哪个网站好文章目录 System V共享内存创建共享内存shmget 控制共享内存shmctl shm特性 System V
System V是Liunx中的重要的进程间通信机制#xff0c;它包括#xff08;shm#xff09;共享内存#xff0c;#xff08;msg#xff09;消息队列和#xff08;sem#xff09;信号量。… 文章目录 System V共享内存创建共享内存shmget 控制共享内存shmctl shm特性 System V
System V是Liunx中的重要的进程间通信机制它包括shm共享内存msg消息队列和sem信号量。本篇博客主要介绍其中最常用的一种方式–共享内存。 共享内存
顾名思义共享内存是一块进程之间可以共享的内存区域由于进程之间都是相互独立的那么这块区域自然而然不是又某个进程开辟的而应该是由操作系统亲自开辟。 如上图共享内存会被进程的页表直接映射到自己的进程地址空间共享区从而通过地址空间与页表直接访问到物理内存可能有多层进而对内存操作这就是多个进程共享一块内存的基本原理。 创建共享内存
shmget
shmget 函数是 shm 中用于创建或获取共享内存段的函数。需要头文件sys/ipc.h和sys/shm.h函数原型如下
int shmget(key_t keysize_t sizeint shmflg)
返回值
shmget返回一个整型这个整型叫做shmid用于标识唯一的shm。 1.key : 标识要创建或获取的共享内存段是System V方式的唯一标识。 注意和shmid区分shmid是用来标识唯一的共享内存(shm)。 2.size : 指定要创建的共享内存段的大小单位为字节 注意共享内存以4kb为基本单位开辟内存因此开辟内存的时候这个参数最好设置为4096的倍数哪怕你只是申请了一个字节的内存实际上还是会开辟4kb大小的空间的。 3 . shmflg : 用于指定共享内存段访问的权限和其他选项。 这是一个用于控制共享内存的开辟方式以及各个属性的选项本质上是一个位图。
IPC_CREAST 如果指定的key不存在则创建一个新的共享内存段如果已经存在则直接获取原先的共享内存。IPC_EXCL如果指定的key已经存在则创建失败。
要注意IPC_EXCL只能配合IPC_CREAT一起使用不能单独使用。
还可以按照权限值的8进制位或到第三个参数之中。
int main()
{int shmid shmget(1, 4096, IPC_CREAT | IPC_EXCL | 0666);return 0;
}如果只想看共享内存的方式则ipcs -m:
一开始存在一个shmid 0的共享内存之后通过指令的方式删除掉了这个共享方式除了这种方式我们还可以通过系统接口来删除共享内存也就是下面要介绍的shmctl接口。 控制共享内存
shmctl
shmctl 用于控制共享内存的各种属性。 获取共享内存段的状态信息修改共享内存段的属性删除共享内存段 shmctl包含在头文件sys/ipc.h和sys/shm.h中函数原型如下
int shmctl(int shmid, int cmd, struct shmid_ds *buf);函数返回值
shmctl 函数的返回值用于指示操作是否成功
成功时返回 0表示操作已完成且未发生错误。失败时返回 -1并设置 errno 变量以指示具体的错误原因。常见的错误包括权限不足、无效的共享内存标识符等。
shmctl 函数有三个主要参数它们共同决定了函数的行为 shmid这是要操作的共享内存段的标识符。通过 shmget 函数可以获取该标识符它是后续所有操作的基础确保函数作用于正确的共享内存段。 cmd指定要执行的操作类型它可以是以下值之一 IPC_STAT用于获取共享内存段的状态信息。此操作会将共享内存段的相关属性填充到由 buf 指向的 shmid_ds 结构体中供程序查询和分析。IPC_SET用于设置共享内存段的某些属性。通过 buf 参数传递新的属性值但需注意只有超级用户或拥有适当权限的进程才能执行此操作。IPC_RMID用于删除共享内存段。执行此操作后共享内存段将被标记为可销毁系统会在合适的时候将其从内核中移除。 buf这是一个指向 shmid_ds 结构体的指针。当 cmd 参数为 IPC_STAT 时该结构体用于接收共享内存段的当前属性当 cmd 参数为 IPC_SET 时该结构体则包含需要设置的新属性值。
相关结构体 shmid_ds
在使用 shmctl 函数时shmid_ds 结构体是至关重要的它包含了共享内存段的详细信息
struct shmid_ds {struct ipc_perm shm_perm; /* 所有者和权限 */size_t shm_segsz; /* 段的大小字节 */time_t shm_atime; /* 最后附加时间 */time_t shm_dtime; /* 最后分离时间 */time_t shm_ctime; /* 最后更改时间 */pid_t shm_cpid; /* 创建者的 PID */pid_t shm_lpid; /* 最后调用 shmat/shmdt 的 PID */shmatt_t shm_nattch; /* 当前附加次数 */...
};shm_perm该字段是一个 ipc_perm 结构体包含了共享内存段的所有者、组、权限等信息用于控制进程对共享内存段的访问权限。shm_segsz表示共享内存段的大小以字节为单位。在创建共享内存段时设置后续操作中可通过 IPC_STAT 获取该值或在有适当权限时通过 IPC_SET 修改。时间相关字段shm_atime、shm_dtime、shm_ctime分别记录了共享内存段最后被附加、分离以及更改的时间这些信息对于监控共享内存段的使用情况非常有用。进程 ID 相关字段shm_cpid、shm_lpidshm_cpid 是创建共享内存段的进程的 PID而 shm_lpid 是最后调用 shmat 或 shmdt 函数的进程的 PID有助于追踪共享内存段的使用历史。shm_nattch表示当前共享内存段被附加的次数。当进程调用 shmat 附加共享内存段时该值会增加当进程调用 shmdt 分离共享内存段时该值会减少。当该值为 0 时表示没有进程正在使用该共享内存段。 当shmctl第二个参数cmd为IPC_STAT此时就可以获取一个共享内存的基本信息。 示例 :
int main()
{int id shmget(1, 4096, IPC_CREAT | IPC_EXCL | 0666);struct shmid_ds shm;shmctl(id, IPC_STAT, shm);cout atime: shm.shm_atime endl;cout ctime: shm.shm_ctime endl;cout cpid: shm.shm_cpid endl;return 0;
}第二个参数为IPC_SET时候可以设置共享内存的某些属性。 int main()
{int id shmget(1, 4096, IPC_CREAT | IPC_EXCL | 0666);struct shmid_ds shm;shmctl(id, IPC_STAT, shm);cout atime: shm.shm_atime endl;// 140731859906331shm.shm_atime 1 ;//修改shm信息shmctl(id, IPC_SET, shm);//重新获取shm信息shmctl(id, IPC_STAT, shm);cout atime: shm.shm_atime endl;// 1return 0;
}
删除共享内存通过接口的方式 int main()
{shmctl(0, IPC_RMID, nullptr);return 0;
} 一开始存在一个shmid 0 的共享内存经过test之后这个共享内存就被删除了。 上面我们详细讨论了如何来开辟一个共享内存还没有真正使用这段共享内存来进行通信。
接下来假设现在有AB两个进程他们通过共享内存的方式进行通信其中A负责发送消息B负责接收消息。
A进程的代码数据如下
int main()
{key_t key ftok(./test.cpp, 1);int shmid shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);char* ptr (char*)shmat(shmid, nullptr, 0);for(int ch A; ch Z; ch){ptr[ch - A] ch;sleep(1);}shmctl(shmid, IPC_RMID, nullptr);return 0;
}B进程的代码数据如下
int main()
{key_t key ftok(./test.cpp, 1);int shmid shmget(key, 4096, IPC_CREAT);char* ptr (char*)shmat(shmid, nullptr, 0);while(true){cout ptr endl;sleep(5);}return 0;
} 可以看到A向共享内存中写入数据就被B进程读到了 shm特性
共享内存有以下一些主要特性 内存共享多个进程可以同时访问和修改同一块共享内存区域。这种共享内存机制可以让进程之间高效地交换数据,而无需通过系统调用或者其他进程间通信机制。 快速访问相比于其他进程间通信机制如管道、消息队列等共享内存的访问速度更快因为数据直接存储在内存中不需要进行数据的拷贝和上下文切换。 灵活性共享内存可以在进程之间自由分配和管理大小和位置都可以灵活设置。这种灵活性使得共享内存非常适合用于复杂的进程间通信场景。 同步问题多个进程可以并发访问和修改共享内存因此需要使用信号量、互斥锁等同步机制来协调对共享内存的访问避免数据竞争和不一致性问题。 内存分配共享内存是由内核管理的进程无法直接分配和释放共享内存必须通过系统调用如 shmget() 和 shmctl() 来完成。 system V 的后两种通信方式 消息队列 msg 和 信号量 sem 都非常不常用了不深入研究。