C语言中共享内存完整示例示例

 更新时间:2025年11月17日 09:49:26   作者:山,离天三尺三  
本文主要介绍了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
等待读取进程读取数据...

注意事项

  • 同步问题:共享内存需要额外的同步机制(信号量、互斥锁等)
  • 资源清理:确保进程退出前分离共享内存
  • 权限设置:根据安全需求设置适当的权限
  • 错误处理:检查所有系统调用的返回值
  • 内存对齐:考虑数据结构的内存对齐问题

到此这篇关于C语言中共享内存完整示例示例的文章就介绍到这了,更多相关C语言 共享内存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言八大排序之堆排序

    C语言八大排序之堆排序

    堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序
    2022-02-02
  • C++静态变量,常量的存储位置你真的了解吗

    C++静态变量,常量的存储位置你真的了解吗

    这篇文章主要介绍了C++中静态变量与常量的存储位置的相关资料,需要的朋友可以参考下,希望能够给你带来帮助
    2021-08-08
  • Visual Studio调试C/C++教程指南

    Visual Studio调试C/C++教程指南

    VisualStudio是微软开发的一款集成开发环境软件,本文主要介绍了Visual Studio调试C/C++教程指南,熟悉地掌握基于VS的C/C++调试技术,可以大幅提升调试性能,感兴趣的可以了解一下
    2024-06-06
  • C++ 字符串string和整数int的互相转化操作

    C++ 字符串string和整数int的互相转化操作

    这篇文章主要介绍了C++ 字符串string和整数int的互相转化操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • C++ 实现静态链表的简单实例

    C++ 实现静态链表的简单实例

    这篇文章主要介绍了C++ 实现静态链表的简单实例的相关资料,需要的朋友可以参考下
    2017-06-06
  • C++解决合并两个排序的链表问题

    C++解决合并两个排序的链表问题

    本文主要介绍了通过C++解决合并两个排序的链表并使新链表中的节点仍然是递增排序的。文中代码讲解详细,有需要的朋友可以参考一下
    2021-12-12
  • c语言内存泄露示例解析

    c语言内存泄露示例解析

    从1988年著名的莫里斯蠕虫 攻击到有关 Flash Player 和其他关键的零售级程序的最新安全警报都与缓冲区溢出有关:“大多数计算机安全漏洞都是缓冲区溢出”,Rodney Bates 在 2004 年写道
    2013-09-09
  • C++读写配置项的基本操作

    C++读写配置项的基本操作

    这篇文章主要介绍了C++读写配置项的基本操作,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下
    2021-01-01
  • C++利用stringstream进行数据类型转换实例

    C++利用stringstream进行数据类型转换实例

    这篇文章主要介绍了C++利用stringstream进行数据类型转换的方法,实例分析了使用stringstream进行string转int的操作技巧,需要的朋友可以参考下
    2015-01-01
  • C++实现LeetCode(99.复原二叉搜索树)

    C++实现LeetCode(99.复原二叉搜索树)

    这篇文章主要介绍了C++实现LeetCode(99.复原二叉搜索树),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07

最新评论