C语言-进程间通信—共享内存的入门

前言

进程间通信(Inter-Process Communication, IPC)是操作系统中实现多进程协同工作的重要手段之一。在多种IPC方式中,共享内存因其高效、灵活的特性而受到广泛关注。本文将介绍C语言中共享内存的基本概念、使用方法和注意事项,帮助读者入门共享内存的使用。

一、共享内存的基本概念

共享内存是指两个或多个进程共享一个给定的存储区。因为进程可以直接读写内存,所以这是最快的一种IPC方式。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

二、C语言中共享内存的使用

共享内存,顾名思义就是开辟一段内存,让多个进程能对其进行读写。我们常有几个操作:创建共享内存、连接共享内存、断开连接共享内存、删除共享内存。

1、创建共享内存

使用shmget函数可以创建共享内存。

函数信息

我们查看man手册中,shmget函数的信息如下:

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

int shmget(key_t key, size_t size, int shmflg);

参数介绍

  • key:用于唯一标识共享内存段的键值。
  • size:共享内存的大小,以字节为单位。
  • shmflg:权限标志位和IPC_CREAT标志的组合。

返回值

On success, a valid shared memory identifier is returned.  On error, -1
       is returned, and errno is set to indicate the error.

成功会返回一个共享内存的标识符,如果错误会返回-1。

2. 连接到共享内存

使用shmat函数可以将共享内存连接到进程的地址空间。

函数信息

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

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数介绍

  • shmid:由shmget`返回的共享内存标识符。
  • shmaddr:指定共享内存连接到进程地址空间的起始地址,通常设置为NULL。
  • shmflg:标志位,通常设置为0。

返回值

On  success,  shmat() returns the address of the attached shared memory
       segment; on error, (void *) -1 is returned, and errno is set  to  indi‐
       cate the cause of the error.

3.断开共享内存连接

使用shmdt函数可以断开共享内存与进程的连接。

函数信息

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

int shmdt(const void *shmaddr);

参数介绍

  • shmaddrshmat返回的指向共享内存的指针。

4. 删除共享内存

当不再需要共享内存时,使用shmctl函数配合IPC_RMID命令可以删除它。

函数信息

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

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数介绍

  • shmid:共享内存标识符。
  • cmd:要执行的操作,如IPC_RMID用于删除共享内存。
  • buf:指向shmid_ds结构的指针,用于获取或设置共享内存的属性,我们一般不怎么关心,设置成0

三、使用案例

写信息入共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//       int shmget(key_t key, size_t size, int shmflg);
int main()
{
	char *memmary;
	key_t key;
	key = ftok(".",1);
	int shmid = shmget(key,1024*4,IPC_CREAT|0666);

	memmary = shmat(shmid,0,0);
	strcpy(memmary,"hello word\n");
	sleep(5);

	shmdt(memmary);
	shmctl(shmid,IPC_RMID,0);
	printf("done \n");
	return 0;
}

这个代码,我们先创建了一个共享内存,然后连接到这个共享内存,利用strcpy函数将字符串写入共享内存中,然后我们挂起程序5s等待其他程序将共享内存读走。然后断开连接并删除了共享内存。

读取共享内存里的信息

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//       int shmget(key_t key, size_t size, int shmflg);
int main()
{
	char *memmary;
	key_t key;
	key = ftok(".",1);
	int shmid = shmget(key,1024*4,0);

	memmary = shmat(shmid,0,0);

	printf("get memmary:%s",memmary);
	shmdt(memmary);
	return 0;
}

这段代码我们连接上了同一个共享内存,然后读取里面的值后输出。



四、Linux中操作共享内存

常用命令

1、ipcs -m

通过这个命令我们可以看到共享内存的信息:

------------ 共享内存段 --------------
键        shmid      拥有者  权限     字节     连接数  状态      
0x0103c0ec 7          hyx        666        4096       0

2、ipcrm -m [key]

通过该命令,我们可以删除指定key的共享内存



五、注意事项

  1. 同步问题:多个进程同时读写共享内存时,必须解决同步问题,以防止数据竞争和不一致。通常可以使用信号量(semaphores)或互斥锁(mutexes)来实现同步。
  2. 权限管理:创建共享内存时,需要设置适当的权限,以确保只有授权的进程能够访问。
  3. 错误处理:在使用共享内存相关函数时,应检查返回值以处理可能出现的错误。
  4. 内存管理:虽然共享内存提供了高效的进程间通信方式,但也需要谨慎管理内存,避免内存泄漏和其他内存相关的问题。

总结

共享内存是一种高效的进程间通信方式,它允许不同进程直接访问同一块内存区域。通过C语言的IPC相关函数,我们可以方便地创建、连接、断开和删除共享内存。然而,在使用共享内存时,我们需要注意同步问题、权限管理、错误处理以及内存管理等方面的问题,以确保程序的正确性和安全性。

本文介绍了共享内存的基本概念和使用方法,希望能为读者入门共享内存提供一定的帮助。在实际使用中,建议参考操作系统的相关文档和资料,以获得更详细和深入的了解。