1. Linux下的共享内存介绍
共享内存是一种进程间通信的方式,可以实现多个进程之间对同一块内存地址的直接访问。在Linux中,共享内存是一种高速的进程间通信方式,它不需要复制数据,进程可以直接读写共享内存,大大提高了程序的效率。
共享内存的使用需要先创建一块共享内存区域,然后进程可以通过访问这块共享内存区域来实现数据共享。在Linux系统中,我们可以使用系统调用shmget、shmat、shmdt和shmctl来创建、连接、断开和删除共享内存。
2. 查看共享内存信息
2.1. 使用ipcs命令
ipcs命令可以用来查看共享内存的信息,包括共享内存的标识符、键值、尺寸、创建者、连接数等。使用以下命令可以查看当前系统中的共享内存:
ipcs -m
该命令会列出系统中所有共享内存的信息,我们可以根据需求查找我们关心的共享内存。
例如,以下是一个示例输出:
T ID KEY MODE OWNER GROUP CPID LPID CUID CGID NATTCH SEGSZ CPUSZ GMTIME
m 32768 0x12345678 --rw-rw-rw- user1 group1 12345 12345 user1 group1 1 4096 4096 Fri Mar 1 15:00:00 2023
m 32769 0x87654321 --rw-rw-rw- user2 group2 54321 54321 user2 group2 2 8192 8192 Fri Mar 1 16:00:00 2023
通过ipcs命令,我们可以看到共享内存的ID、键值、权限信息、创建者、连接数、共享内存大小等。
2.2. 使用proc文件系统
Linux提供了proc文件系统,通过读取/proc/sysvipc/shm文件来获取共享内存信息。可以使用以下命令查看共享内存:
cat /proc/sysvipc/shm
此命令会显示共享内存的相关信息,例如:
key shmid perms size cpid lpid nattch status
0x12345678 32768 666 4096 12345 12345 1 dest (deleted)
0x87654321 32769 666 8192 54321 54321 2 dest
通过读取/proc/sysvipc/shm文件,我们可以获取到共享内存的键值、共享内存ID、权限、大小、创建者进程ID、连接进程ID等信息。
3. 使用共享内存
3.1. 创建共享内存
在Linux中,我们可以使用shmget系统调用来创建共享内存。shmget函数的原型如下:
int shmget(key_t key, size_t size, int shmflg);
其中,key是共享内存的键值,可以使用ftok函数生成;size是共享内存的大小;shmflg是共享内存的权限标志,可以使用IPC_CREAT标志来创建新共享内存。
示例代码如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 4096
int main() {
key_t key = ftok("shmfile", 'A'); // 生成键值
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666); // 创建共享内存
if (shmid == -1) {
perror("shmget");
return -1;
}
printf("Shared memory ID: %d\n", shmid);
return 0;
}
上述代码通过ftok函数生成键值,并使用shmget创建一个大小为4096字节的共享内存。如果创建成功,shmget函数会返回共享内存ID,我们可以通过该ID来访问共享内存。
3.2. 连接共享内存
在Linux中,我们可以使用shmat系统调用来连接共享内存。shmat函数的原型如下:
void *shmat(int shmid, const void *shmaddr, int shmflg);
其中,shmid是共享内存的ID;shmaddr是共享内存连接的地址,一般为NULL,让系统选择合适的地址;shmflg是共享内存访问标志,一般为0。
示例代码如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
key_t key = ftok("shmfile", 'A'); // 生成键值
int shmid = shmget(key, SHM_SIZE, 0666); // 创建共享内存
if (shmid == -1) {
perror("shmget");
return -1;
}
void *shmaddr = shmat(shmid, NULL, 0); // 连接共享内存
if (shmaddr == (void *)-1) {
perror("shmat");
return -1;
}
printf("Shared memory address: %p\n", shmaddr);
return 0;
}
上述代码中,我们使用shmat函数连接了先前创建的共享内存,并通过打印共享内存地址来验证连接成功。
3.3. 使用共享内存
在连接共享内存后,我们可以通过指针来访问共享内存的数据。需要注意的是,共享内存的指针指向的是原始数据,因此必须自己处理数据的格式等问题。
以下是一个简单的示例,演示了一个进程将数据写入共享内存,另一个进程读取并打印共享内存中的数据:
#include <string.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 4096
typedef struct {
char name[20];
int age;
} Person;
int main() {
key_t key = ftok("shmfile", 'A'); // 生成键值
int shmid = shmget(key, SHM_SIZE, 0666); // 创建共享内存
if (shmid == -1) {
perror("shmget");
return -1;
}
void *shmaddr = shmat(shmid, NULL, 0); // 连接共享内存
if (shmaddr == (void *)-1) {
perror("shmat");
return -1;
}
Person *person = (Person *)shmaddr; // 指针转换
strcpy(person->name, "Alice"); // 写入数据
person->age = 20;
// 读取数据
printf("Name: %s\n", person->name);
printf("Age: %d\n", person->age);
shmdt(shmaddr); // 断开共享内存连接
return 0;
}
上述代码中,我们定义了一个Person结构体,然后将共享内存指针转换为Person类型的指针,实现对共享内存数据的写入和读取。
4. 删除共享内存
在使用完共享内存后,我们需要手动删除共享内存以释放资源。在Linux中,可以使用shmctl系统调用来删除共享内存。shmctl函数的原型如下:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
其中,shmid是共享内存的ID;cmd是需要执行的操作,可以使用IPC_RMID来删除共享内存;buf是shmid_ds结构的指针,用于获取共享内存的信息,一般为NULL。
示例代码如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
key_t key = ftok("shmfile", 'A'); // 生成键值
int shmid = shmget(key, SHM_SIZE, 0666); // 创建共享内存
if (shmid == -1) {
perror("shmget");
return -1;
}
if (shmctl(shmid, IPC_RMID, NULL) == -1) { // 删除共享内存
perror("shmctl");
return -1;
}
printf("Shared memory removed\n");
return 0;
}
上述代码中,我们使用shmctl函数删除了先前创建的共享内存,并通过打印信息来验证删除成功。
5. 总结
共享内存是Linux下一种高速的进程间通信方式,可以实现多个进程之间对同一块内存地址的直接访问。本文介绍了如何在Linux下查看、使用和删除共享内存的方法,包括使用ipcs命令和读取/proc/sysvipc/shm文件查看共享内存信息,使用shmget创建共享内存,使用shmat连接共享内存,以及使用shmctl删除共享内存。通过本文的介绍,读者可以了解到共享内存的基本使用方法,并在实际开发中灵活运用。