当前位置:   article > 正文

多进程编程(四):共享内存_多进程 shared

多进程 shared
定义:

共享内存(Shared Memory)就是允许两个或多个进程访问同一个内存空间,是在多进程通信的最高效的方式。
操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。由于共享内存会成为进程用户空间的一部分,所有这种通信方式不需要内核介入。
共享内存并未提供锁机制,也就是说,在某一个进程对共享内存的进行读写的时候,不会阻止其它的进程对它的读写,可能会出现数据的错乱。

函数:

1、必备头文件

#include <sys/ipc.h>
#include <sys/shm.h>
  • 1
  • 2

2、shmget() 获取或创建共享内存

// 获取或者创建共享内存
int shmget(key_t key, size_t size, int shmflg);
- key是共享内存的键值,是一个整数,是共享内存在系统中的编号,不同共享内存的编号不同。一般使用十六进制。
- size表示待创建共享内存的大小,以字节为单位
- shmflg表示共享内存的访问权限,与文件的权限一样,
	0666 | IPC_CREAT 表示全部用户对它可读写
- 返回值:返回共享内存标识
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3、shmat() 把共享内存连接到当前进程的地址空间

void *shmat(int shm_id, const void *shm_addr, int shmflg);
- shm_id表示由 shmget函数返回的 共享内存的标识号
- shm_addr指定共享内存连接到当前进程中的地址位置,通常为 NULL,表示让系统来选择共享内存的地址。
- shm_flg是一组标志位,通常为0
- 返回值:
	调用成功:返回一个指向共享内存第一个字节的指针
	调用失败:返回 -1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4、shmdt() 将共享内存从当前进程中分离,相当于 shmat()函数的反操作

int shmdt(const void *shmaddr);
- shmaddr是 shmat函数 返回的地址
- 返回值:
	调用成功:返回 0
	调用失败:返回 -1
  • 1
  • 2
  • 3
  • 4
  • 5

5、shmctl() 删除共享内存

int shmctl(int shm_id, int command, struct shmid_ds *buf);
- shm_id是共享内存的标识号
- command 填写 IPC_RMID
- buf 填写 0
- 返回值:
	调用成功:返回 0
	调用失败:返回 -1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
使用步骤
  • 调用 shmget() 函数创建一个新共享内存段或取得一个现有的共享内存段的标识号。返回后续可调用的需要用到的共享内存标识符。
  • 在进程中使用 shmat() 函数附上共享内存段,即让该共享内存段成为调用进程的虚拟内存中的一部分(进程绑定共享内存段)
  • 使用 shmat() 返回的内存地址指针,就可以在程序中对该共享内存段进行操作(写操作/读操作)。
  • 调用 shmdt() 函数,让进程和共享内存段分离,进程无法再操作共享内存了。(只是分离,共享内存依然存在)
  • 调用 shmctl() 函数,删除共享内存段,只有当与该共享内存段绑定好的进程都分离后,才会销毁,只有一个进程需要执行这一步。
举例
// write_shm.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h> 

int main()
{
	int shmid; // 共享内存标识符
 
  	// 创建共享内存,键值为0x5005,共1024字节。
  	if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1)
  	{ 
		printf("shmat(0x5005) failed\n"); 
		return -1; 
	}

  	char *ptext = NULL;   // 用于指向共享内存的指针
 
  	// 将共享内存连接到当前进程的地址空间,由ptext指针指向它
  	ptext = (char *)shmat(shmid, NULL, 0);
    
  	// 操作本程序的ptext指针,就是操作共享内存
    char *str = "Hello world!";
  	memcpy(ptext, str, strlen(str));
    
  	// 把共享内存从当前进程中分离
  	shmdt(ptext);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
// read_shm.c

int main()
{
	int shmid; // 共享内存标识符
 
  	// 创建共享内存,键值为0x5005,共1024字节。
  	if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1)
  	{ 
		printf("shmat(0x5005) failed\n"); 
		return -1; 
	}

  	char *ptext = NULL;   // 用于指向共享内存的指针
 
  	// 将共享内存连接到当前进程的地址空间,由ptext指针指向它
  	ptext = (char *)shmat(shmid, NULL, 0);
 
  	// 操作本程序的ptext指针,就是操作共享内存
  	printf("%s\n", ptext);
 
  	// 把共享内存从当前进程中分离
  	shmdt(ptext);
   
  	// 删除共享内存
  	if (shmctl(shmid, IPC_RMID, 0) == -1)
  	{ 
		printf("shmctl(0x5005) failed\n"); 
		return -1; 
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

read_shm.c的输出结果:

Hello world!
  • 1

可以看出,write_shm.c 申请共享内存,并写入数据,read_shm获取共享内存标识号,并绑定进程,读取该共享内存中的数据。

查看共享内存
ipcs -m # 查看现有的所有共享内存段

ipcrm -m shmid # 根据共享内存段的标识号,删除共享内存
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/566307
推荐阅读
相关标签
  

闽ICP备14008679号