linux多进程基础(7):共享进程:shmget(),shmat(),shmdt(),shmctl()

linux多进程基础(7):共享进程:shmget(),shmat(),shmdt(),shmctl()共享进程 shmget shmat shmdt shmctl shmget

大家好,欢迎来到IT知识分享网。

为什么要引入共享进程

共享进程顾名思义,就是允许多个程序共同使用一个进程。共享内存是进程间通信最快的方式,仅在建立共享内存区域时需要系统调用,以后所有共享内存访问都处理为常规内存访问。为此,为了节省系统资源,提高进程间通信速度,我们需要引入共享进程的概念.

共享进程常用的函数共有四个:shmget(),shmat(),shmdt(),shmctl().我将依次介绍.

1.shmget()

shmget()函数是用于获取共享内存段的标识符的系统调用 ,其定义如下:

#include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);

其中key代表共享内存的键值,通常由ftok()函数生成;size为共享内存的大小(以字节为单位;shmflg为共享内存的权限标志,常用的权限标志有IPC_CREATIPC_EXCL0666等。

若执行成功,shmget()函数返回共享内存的标识符(一个非负整数)。如果失败,返回-1并设置相应的错误码。 

2.shmctl()

shmctl()函数用于对共享内存进行控制操作,如初始化、删除等,其定义如下:

#include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf);

其中,shmid为共享内存的标识符,由shmget()函数返回;cmd为指定要执行的操作命令。常用的命令有IPC_RMID(删除共享内存段)等;buf为指向shmid_ds结构的指针,用于设置或获取共享内存的属性。

若执行成功,shmctl()函数返回0。如果失败,返回-1。

3.shmat()

 shmat()函数用于将共享内存连接到当前进程的地址空间中。其定义如下:

#include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg);

其中,shmid为共享内存的标识符,由shmget()函数返回;shmaddr为指定共享内存连接到当前进程的地址空间的起始地址。如果这个参数为NULL,系统会自动选择一个合适的地址;shmflg为指定连接共享内存的权限标志,常用的权限标志有SHM_RDONLY(只读连接)等。

若执行成功shmat()函数返回一个指向共享内存的指针。如果失败,返回(void *) -1。

4.shmdt()

shmdt()函数是用于用于将共享内存从当前进程的地址空间中分离。其定义如下:

#include <sys/shm.h> int shmdt(const void *shmaddr);

其中,shmaddr为指定要分离的共享内存的地址。这个地址是由shmat()函数返回的指针。

若执行成功shmdt()函数返回0。如果失败,返回-1并设置相应的错误码。

5.举例

 我将通过使用这四个函数,来实现一个小项目,项目的目的是:创建一个大小为1024字节的共享内存段,将数字0到9转换为字符并存储到该共享内存中,然后从当前进程中打印出该字符串,最后删除共享内存段。

#include <stdio.h> // 引入标准输入输出库,用于printf函数 #include <stdlib.h> // 引入标准库,用于exit函数 #include <string.h> // 引入字符串处理库,用于strlen函数 #include <sys/ipc.h> // 引入System V IPC库的头文件,用于ftok、shmget、shmat、shmdt和shmctl函数 #include <sys/shm.h> // 引入共享内存相关的头文件 #include <sys/types.h> // 引入系统类型定义的头文件 #include <sys/unistd.h> // 引入POSIX线程库的头文件,虽然这里并未使用到线程相关的功能 #include <iostream> // 引入C++标准库,用于iostream类 int main(){ // 主函数入口点 int shm; // 声明一个整型变量shm,用于存储共享内存标识符 key_t key; // 声明一个key_t类型的变量key,用于存储IPC键值 key=ftok(".", 'R'); // 使用ftok函数生成一个唯一的IPC键值,'R'是生成键值的字符,"./"是基路径 char * buff; // 声明一个字符指针变量buff,用于存储共享内存的地址 shm=shmget(key,1024,0666|IPC_CREAT); // 使用shmget函数获取或创建一个大小为1024字节的共享内存段,0666是共享内存的权限设置,IPC_CREAT表示如果该共享内存不存在则创建它 if(shm<0){ // 检查共享内存是否获取成功,如果失败则输出错误信息并退出程序 perror("shmget error"); // 使用perror函数输出错误信息 exit(1); // 使用exit函数退出程序 } buff=(char*) shmat(shm,NULL,0); // 使用shmat函数将共享内存附加到当前进程的地址空间中,NULL参数表示让系统自动选择一个合适的地址,0是shmat函数的标志参数,这里没有使用到该标志位 if (buff == (char *) -1) { // 检查共享内存是否附加成功,如果失败则输出错误信息并退出程序 perror("shmat error"); // 使用perror函数输出错误信息 exit(1); // 使用exit函数退出程序 } for(int i=0;i<10;i++){ // 使用for循环将数字0到9转换为字符并存储到共享内存中,每个数字占用一个字节的空间,所以这里最多只能存储10个数字字符(包括字符串终止符'\0') buff[i]='0'+i; // '0'+i将数字i转换为字符存储到buff[i]中,例如i为0时,'0'+0='0',i为1时,'0'+1='1',以此类推。注意这里的字符'0'实际上是数字字符的ASCII码值48。 } buff[9] = '\0'; // 在字符串的末尾添加一个'\0'字符,作为字符串的终止符。注意这里的数组下标是从0开始的,所以这里实际上是在存储第11个字符。由于之前已经存储了10个数字字符,所以这里存储'\0'字符后字符串就结束了。如果下标超过数组大小会导致数组越界访问,这是一种常见的编程错误。在实际编程中要特别注意数组下标的范围。 printf("%s\n", buff); // 使用printf函数打印共享内存中的字符串。由于之前在字符串末尾添加了'\0'字符作为终止符,所以这里的printf函数会正确地打印出字符串"0"。注意这里的数组下标是从0开始的,所以这里实际上是在打印第10个字符。如果下标超过数组大小会导致数组越界访问,这是一种常见的编程错误。在实际编程中要特别注意数组下标的范围。另外需要注意的是这里的printf函数是使用标准库中的函数,而不是iostream库中的函数。虽然iostream库也可以用于C++中的输入输出操作,但这里使用的是C语言的标准库函数。在实际编程中要根据需要选择合适的库函数。 shmdt(buff); // 使用shmdt函数将共享内存从当前进程的地址空间中分离出来。 shmctl(shm,IPC_RMID,NULL); //shmctl函数删除共享内存段 return 0; }

运行代码得到结果:

linux多进程基础(7):共享进程:shmget(),shmat(),shmdt(),shmctl()

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118669.html

(0)
上一篇 2025-11-11 14:00
下一篇 2025-11-11 14:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信