当前位置: 首页 > news >正文

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一起使用,如果已存在则失败

    • 权限标志: 06660600等(八进制)

返回值:

  • 成功: 共享内存标识符

  • 失败: -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: 共享内存ID

  • int cmd: 控制命令

    • IPC_STAT: 获取状态信息到buf

    • IPC_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

运行步骤:

  1. 先运行写入进程

./writer
  1. 再运行读取进程(新终端):

./reader

运行结果示例:

=== 共享内存写入进程 ===
创建共享内存成功, shmid = 98304
=== 共享内存信息 ===
共享内存ID: 98304
键值: 0x1234
大小: 1024 字节
创建者PID: 1234
最后操作PID: 0
附加进程数: 0
...
写入数据: 这是第 1 条消息 - 时间戳: 1634567890
等待读取进程读取数据...

注意事项

  1. 同步问题:共享内存需要额外的同步机制(信号量、互斥锁等)

  2. 资源清理:确保进程退出前分离共享内存

  3. 权限设置:根据安全需求设置适当的权限

  4. 错误处理:检查所有系统调用的返回值

  5. 内存对齐:考虑数据结构的内存对齐问题

http://www.dtcms.com/a/619614.html

相关文章:

  • 创新网站建设论文wordpress 中文 插件
  • 在工商局网站如果做注销公告11电影网
  • 南头专业外贸网站建设公司绿色郑州网站
  • 餐饮酒店网站建设网页传奇网址
  • 网站建设 客户评价泰州网站专业制作
  • 电子商务网站概念食品网站建设目的
  • 携程前端开发200道题面经及参考答案(上)
  • 深圳最好的网站建设公司排名建站公司前景
  • 郑州免费网站制作沈阳网络公司排名
  • 易捷网站内容管理系统漏洞太原网站搜索优化
  • 网站投注建设网页设计作业制作个人网站
  • 软件公司网站模板下载广告设计制作属于什么行业
  • 成都科技网站建设咨询电话湛江建站服务
  • 域名先解析后做网站帮做非法网站
  • CSS 自定义属性与滤镜:打造动态视觉效果的现代 Web 技术
  • 做自己的卡盟网站网站开发需要什么
  • 电子商务网站模版做图模板网站有哪些
  • 网站建设做什么会计分录厦门做企业网站比较好的公司
  • 扫码支付做进商城网站南京建设工程交易中心网站
  • 巩义做网站长沙网站设计培训学校
  • QC七大手法之柏拉图
  • 阜阳建设网站公司电话做网站找公司怎么找
  • [C#] NO.4 我的第一个C#项目
  • linux root节点解析
  • 14.vector(上)
  • 烟台网站建设开发网站正在建设中永久
  • 快速搭建网站框架图互联网产品运营推广方案
  • Golang学习第一天笔记总结
  • 用jsp实现网站开发实例wordpress去除评论
  • 【Java常用API】-----System 与 标准 I/O流