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

定义:

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

函数:

1、必备头文件

#include <sys/ipc.h>
#include <sys/shm.h>

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

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

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

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

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

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

5、shmctl() 删除共享内存

int shmctl(int shm_id, int command, struct shmid_ds *buf);
- shm_id是共享内存的标识号
- command 填写 IPC_RMID
- buf 填写 0
- 返回值:
	调用成功:返回 0
	调用失败:返回 -1

使用步骤

  • 调用 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;
}
// 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; 
	}
}

read_shm.c的输出结果:

Hello world!

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

查看共享内存

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

ipcrm -m shmid # 根据共享内存段的标识号,删除共享内存

猜你喜欢

转载自blog.csdn.net/Sir666888/article/details/125460499
今日推荐