C语言中共享内存完整示例示例
作者:山,离天三尺三
本文主要介绍了C语言中共享内存完整示例示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
完整的共享内存通信示例
头文件 (shm_common.h)
#ifndef __SHM_COMMON_H__
#define __SHM_COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <errno.h>
#define SHM_KEY 0x1234 // 共享内存键值
#define SHM_SIZE 1024 // 共享内存大小
#define MAX_DATA_SIZE 512 // 最大数据长度
// 共享内存数据结构
struct shm_data {
int written; // 数据写入标志: 0-未写入, 1-已写入
char data[MAX_DATA_SIZE]; // 数据缓冲区
};
// 函数声明
int create_shared_memory(key_t key, size_t size, int flags);
void* attach_shared_memory(int shmid);
int detach_shared_memory(const void *shm_addr);
int destroy_shared_memory(int shmid);
void print_shared_memory_info(int shmid);
#endif写入进程 (writer.c)
#include "shm_common.h"
int main() {
printf("=== 共享内存写入进程 ===\n");
// 1. 创建共享内存
int shmid = create_shared_memory(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
if (shmid == -1) {
perror("创建共享内存失败");
exit(EXIT_FAILURE);
}
printf("创建共享内存成功, shmid = %d\n", shmid);
// 2. 显示共享内存信息
print_shared_memory_info(shmid);
// 3. 附加共享内存到进程
struct shm_data *shared_data = (struct shm_data*)attach_shared_memory(shmid);
if (shared_data == (void*)-1) {
perror("附加共享内存失败");
destroy_shared_memory(shmid);
exit(EXIT_FAILURE);
}
printf("附加共享内存成功\n");
// 4. 向共享内存写入数据
printf("开始向共享内存写入数据...\n");
// 初始化共享内存区域
memset(shared_data, 0, sizeof(struct shm_data));
for (int i = 1; i <= 5; i++) {
// 准备数据
snprintf(shared_data->data, MAX_DATA_SIZE,
"这是第 %d 条消息 - 时间戳: %ld", i, time(NULL));
// 标记数据已写入
shared_data->written = 1;
printf("写入数据: %s\n", shared_data->data);
// 等待读取进程读取
printf("等待读取进程读取数据...\n");
sleep(2);
// 等待数据被读取
while (shared_data->written == 1) {
usleep(100000); // 等待100ms
}
printf("数据已被读取,准备写入下一条...\n\n");
}
// 5. 写入结束标志
strcpy(shared_data->data, "END");
shared_data->written = 1;
printf("写入结束标志\n");
// 6. 清理资源
sleep(1); // 确保读取进程收到结束标志
detach_shared_memory(shared_data);
destroy_shared_memory(shmid);
printf("写入进程结束\n");
return 0;
}读取进程 (reader.c)
#include "shm_common.h"
int main() {
printf("=== 共享内存读取进程 ===\n");
// 1. 获取已存在的共享内存
int shmid = create_shared_memory(SHM_KEY, SHM_SIZE, 0666);
if (shmid == -1) {
perror("获取共享内存失败");
exit(EXIT_FAILURE);
}
printf("获取共享内存成功, shmid = %d\n", shmid);
// 2. 显示共享内存信息
print_shared_memory_info(shmid);
// 3. 附加共享内存到进程
struct shm_data *shared_data = (struct shm_data*)attach_shared_memory(shmid);
if (shared_data == (void*)-1) {
perror("附加共享内存失败");
exit(EXIT_FAILURE);
}
printf("附加共享内存成功\n");
// 4. 从共享内存读取数据
printf("开始从共享内存读取数据...\n\n");
while (1) {
// 等待新数据
if (shared_data->written == 1) {
printf("读取到数据: %s\n", shared_data->data);
// 检查结束标志
if (strcmp(shared_data->data, "END") == 0) {
printf("收到结束标志,停止读取\n");
break;
}
// 标记数据已读取
shared_data->written = 0;
printf("数据已处理,等待下一条数据...\n\n");
} else {
usleep(500000); // 等待500ms再检查
}
}
// 5. 清理资源
detach_shared_memory(shared_data);
printf("读取进程结束\n");
return 0;
}工具函数实现 (shm_common.c)
#include "shm_common.h"
/**
* 创建或获取共享内存段
* @param key: 共享内存键值
* @param size: 共享内存大小
* @param flags: 创建标志和权限
* @return: 成功返回共享内存ID,失败返回-1
*/
int create_shared_memory(key_t key, size_t size, int flags) {
int shmid = shmget(key, size, flags);
if (shmid == -1) {
perror("shmget failed");
}
return shmid;
}
/**
* 将共享内存附加到进程地址空间
* @param shmid: 共享内存ID
* @return: 成功返回共享内存地址,失败返回(void*)-1
*/
void* attach_shared_memory(int shmid) {
void *shm_addr = shmat(shmid, NULL, 0);
if (shm_addr == (void*)-1) {
perror("shmat failed");
}
return shm_addr;
}
/**
* 从进程分离共享内存
* @param shm_addr: 共享内存地址
* @return: 成功返回0,失败返回-1
*/
int detach_shared_memory(const void *shm_addr) {
int result = shmdt(shm_addr);
if (result == -1) {
perror("shmdt failed");
} else {
printf("共享内存分离成功\n");
}
return result;
}
/**
* 销毁共享内存段
* @param shmid: 共享内存ID
* @return: 成功返回0,失败返回-1
*/
int destroy_shared_memory(int shmid) {
int result = shmctl(shmid, IPC_RMID, NULL);
if (result == -1) {
perror("shmctl IPC_RMID failed");
} else {
printf("共享内存销毁成功\n");
}
return result;
}
/**
* 显示共享内存信息
* @param shmid: 共享内存ID
*/
void print_shared_memory_info(int shmid) {
struct shmid_ds shm_info;
if (shmctl(shmid, IPC_STAT, &shm_info) == -1) {
perror("shmctl IPC_STAT failed");
return;
}
printf("=== 共享内存信息 ===\n");
printf("共享内存ID: %d\n", shmid);
printf("键值: 0x%x\n", shm_info.shm_perm.__key);
printf("大小: %lu 字节\n", shm_info.shm_segsz);
printf("创建者PID: %d\n", shm_info.shm_cpid);
printf("最后操作PID: %d\n", shm_info.shm_lpid);
printf("附加进程数: %lu\n", shm_info.shm_nattch);
printf("最后附加时间: %ld\n", shm_info.shm_atime);
printf("最后分离时间: %ld\n", shm_info.shm_dtime);
printf("最后修改时间: %ld\n", shm_info.shm_ctime);
printf("==================\n\n");
}共享内存函数详细说明
1.shmget()- 创建/获取共享内存
int shmget(key_t key, size_t size, int shmflg);
参数说明:
key_t key: 共享内存键值IPC_PRIVATE: 创建私有共享内存ftok()生成: 使用文件路径和项目ID生成
- 自定义整数值: 如0x1234
size_t size: 共享内存大小(字节)int shmflg: 标志和权限的组合IPC_CREAT: 如果不存在则创建IPC_EXCL: 与IPC_CREAT一起使用,如果已存在则失败- 权限标志:
0666,0600等(八进制)
返回值:
- 成功: 共享内存标识符
- 失败: -1,并设置errno
示例:
// 创建新的共享内存 int shmid = shmget(0x1234, 1024, IPC_CREAT | 0666); // 获取已存在的共享内存 int shmid = shmget(0x1234, 0, 0666); // 创建私有共享内存 int shmid = shmget(IPC_PRIVATE, 1024, 0666);
2.shmat()- 附加共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数说明:
int shmid: 共享内存ID(shmget返回值)const void *shmaddr: 指定附加地址NULL: 系统自动选择地址(推荐)- 具体地址: 指定附加到哪个地址
int shmflg: 附加标志SHM_RDONLY: 只读方式附加0: 读写方式附加
返回值:
- 成功: 共享内存附加地址
- 失败:
(void*)-1,并设置errno
示例:
// 读写方式附加 char *shm_addr = shmat(shmid, NULL, 0); // 只读方式附加 char *shm_addr = shmat(shmid, NULL, SHM_RDONLY);
3.shmdt()- 分离共享内存
int shmdt(const void *shmaddr);
参数说明:
const void *shmaddr: 共享内存地址(shmat返回值)
返回值:
- 成功: 0
- 失败: -1,并设置errno
示例:
shmdt(shm_addr);
4.shmctl()- 控制共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数说明:
int shmid: 共享内存IDint cmd: 控制命令IPC_STAT: 获取状态信息到bufIPC_SET: 设置共享内存参数IPC_RMID: 标记删除共享内存SHM_LOCK: 锁定共享内存(防止交换)SHM_UNLOCK: 解锁共享内存
struct shmid_ds *buf: 状态信息缓冲区
返回值:
- 成功: 0
- 失败: -1,并设置errno
示例:
// 删除共享内存 shmctl(shmid, IPC_RMID, NULL); // 获取共享内存信息 struct shmid_ds shm_info; shmctl(shmid, IPC_STAT, &shm_info);
5.ftok()- 生成IPC键值
key_t ftok(const char *pathname, int proj_id);
参数说明:
const char *pathname: 存在的文件路径int proj_id: 项目标识符(0-255)
返回值:
- 成功: IPC键值
- 失败: -1,并设置errno
示例:
key_t key = ftok("/tmp/myapp", 'A');编译和运行
编译命令:
# 编译所有文件 gcc -o writer writer.c shm_common.c gcc -o reader reader.c shm_common.c
运行步骤:
先运行写入进程:
./writer
再运行读取进程(新终端):
./reader
运行结果示例:
=== 共享内存写入进程 ===
创建共享内存成功, shmid = 98304
=== 共享内存信息 ===
共享内存ID: 98304
键值: 0x1234
大小: 1024 字节
创建者PID: 1234
最后操作PID: 0
附加进程数: 0
...
写入数据: 这是第 1 条消息 - 时间戳: 1634567890
等待读取进程读取数据...
注意事项
- 同步问题:共享内存需要额外的同步机制(信号量、互斥锁等)
- 资源清理:确保进程退出前分离共享内存
- 权限设置:根据安全需求设置适当的权限
- 错误处理:检查所有系统调用的返回值
- 内存对齐:考虑数据结构的内存对齐问题
到此这篇关于C语言中共享内存完整示例示例的文章就介绍到这了,更多相关C语言 共享内存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
