C語(yǔ)言中共享內(nèi)存完整示例示例
完整的共享內(nèi)存通信示例
頭文件 (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 // 共享內(nèi)存鍵值
#define SHM_SIZE 1024 // 共享內(nèi)存大小
#define MAX_DATA_SIZE 512 // 最大數(shù)據(jù)長(zhǎng)度
// 共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)
struct shm_data {
int written; // 數(shù)據(jù)寫(xiě)入標(biāo)志: 0-未寫(xiě)入, 1-已寫(xiě)入
char data[MAX_DATA_SIZE]; // 數(shù)據(jù)緩沖區(qū)
};
// 函數(shù)聲明
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寫(xiě)入進(jìn)程 (writer.c)
#include "shm_common.h"
int main() {
printf("=== 共享內(nèi)存寫(xiě)入進(jìn)程 ===\n");
// 1. 創(chuàng)建共享內(nèi)存
int shmid = create_shared_memory(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
if (shmid == -1) {
perror("創(chuàng)建共享內(nèi)存失敗");
exit(EXIT_FAILURE);
}
printf("創(chuàng)建共享內(nèi)存成功, shmid = %d\n", shmid);
// 2. 顯示共享內(nèi)存信息
print_shared_memory_info(shmid);
// 3. 附加共享內(nèi)存到進(jìn)程
struct shm_data *shared_data = (struct shm_data*)attach_shared_memory(shmid);
if (shared_data == (void*)-1) {
perror("附加共享內(nèi)存失敗");
destroy_shared_memory(shmid);
exit(EXIT_FAILURE);
}
printf("附加共享內(nèi)存成功\n");
// 4. 向共享內(nèi)存寫(xiě)入數(shù)據(jù)
printf("開(kāi)始向共享內(nèi)存寫(xiě)入數(shù)據(jù)...\n");
// 初始化共享內(nèi)存區(qū)域
memset(shared_data, 0, sizeof(struct shm_data));
for (int i = 1; i <= 5; i++) {
// 準(zhǔn)備數(shù)據(jù)
snprintf(shared_data->data, MAX_DATA_SIZE,
"這是第 %d 條消息 - 時(shí)間戳: %ld", i, time(NULL));
// 標(biāo)記數(shù)據(jù)已寫(xiě)入
shared_data->written = 1;
printf("寫(xiě)入數(shù)據(jù): %s\n", shared_data->data);
// 等待讀取進(jìn)程讀取
printf("等待讀取進(jìn)程讀取數(shù)據(jù)...\n");
sleep(2);
// 等待數(shù)據(jù)被讀取
while (shared_data->written == 1) {
usleep(100000); // 等待100ms
}
printf("數(shù)據(jù)已被讀取,準(zhǔn)備寫(xiě)入下一條...\n\n");
}
// 5. 寫(xiě)入結(jié)束標(biāo)志
strcpy(shared_data->data, "END");
shared_data->written = 1;
printf("寫(xiě)入結(jié)束標(biāo)志\n");
// 6. 清理資源
sleep(1); // 確保讀取進(jìn)程收到結(jié)束標(biāo)志
detach_shared_memory(shared_data);
destroy_shared_memory(shmid);
printf("寫(xiě)入進(jìn)程結(jié)束\n");
return 0;
}讀取進(jìn)程 (reader.c)
#include "shm_common.h"
int main() {
printf("=== 共享內(nèi)存讀取進(jìn)程 ===\n");
// 1. 獲取已存在的共享內(nèi)存
int shmid = create_shared_memory(SHM_KEY, SHM_SIZE, 0666);
if (shmid == -1) {
perror("獲取共享內(nèi)存失敗");
exit(EXIT_FAILURE);
}
printf("獲取共享內(nèi)存成功, shmid = %d\n", shmid);
// 2. 顯示共享內(nèi)存信息
print_shared_memory_info(shmid);
// 3. 附加共享內(nèi)存到進(jìn)程
struct shm_data *shared_data = (struct shm_data*)attach_shared_memory(shmid);
if (shared_data == (void*)-1) {
perror("附加共享內(nèi)存失敗");
exit(EXIT_FAILURE);
}
printf("附加共享內(nèi)存成功\n");
// 4. 從共享內(nèi)存讀取數(shù)據(jù)
printf("開(kāi)始從共享內(nèi)存讀取數(shù)據(jù)...\n\n");
while (1) {
// 等待新數(shù)據(jù)
if (shared_data->written == 1) {
printf("讀取到數(shù)據(jù): %s\n", shared_data->data);
// 檢查結(jié)束標(biāo)志
if (strcmp(shared_data->data, "END") == 0) {
printf("收到結(jié)束標(biāo)志,停止讀取\n");
break;
}
// 標(biāo)記數(shù)據(jù)已讀取
shared_data->written = 0;
printf("數(shù)據(jù)已處理,等待下一條數(shù)據(jù)...\n\n");
} else {
usleep(500000); // 等待500ms再檢查
}
}
// 5. 清理資源
detach_shared_memory(shared_data);
printf("讀取進(jìn)程結(jié)束\n");
return 0;
}工具函數(shù)實(shí)現(xiàn) (shm_common.c)
#include "shm_common.h"
/**
* 創(chuàng)建或獲取共享內(nèi)存段
* @param key: 共享內(nèi)存鍵值
* @param size: 共享內(nèi)存大小
* @param flags: 創(chuàng)建標(biāo)志和權(quán)限
* @return: 成功返回共享內(nèi)存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;
}
/**
* 將共享內(nèi)存附加到進(jìn)程地址空間
* @param shmid: 共享內(nèi)存ID
* @return: 成功返回共享內(nèi)存地址,失敗返回(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;
}
/**
* 從進(jìn)程分離共享內(nèi)存
* @param shm_addr: 共享內(nèi)存地址
* @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èi)存分離成功\n");
}
return result;
}
/**
* 銷毀共享內(nèi)存段
* @param shmid: 共享內(nèi)存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èi)存銷毀成功\n");
}
return result;
}
/**
* 顯示共享內(nèi)存信息
* @param shmid: 共享內(nèi)存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èi)存信息 ===\n");
printf("共享內(nèi)存ID: %d\n", shmid);
printf("鍵值: 0x%x\n", shm_info.shm_perm.__key);
printf("大小: %lu 字節(jié)\n", shm_info.shm_segsz);
printf("創(chuàng)建者PID: %d\n", shm_info.shm_cpid);
printf("最后操作PID: %d\n", shm_info.shm_lpid);
printf("附加進(jìn)程數(shù): %lu\n", shm_info.shm_nattch);
printf("最后附加時(shí)間: %ld\n", shm_info.shm_atime);
printf("最后分離時(shí)間: %ld\n", shm_info.shm_dtime);
printf("最后修改時(shí)間: %ld\n", shm_info.shm_ctime);
printf("==================\n\n");
}共享內(nèi)存函數(shù)詳細(xì)說(shuō)明
1.shmget()- 創(chuàng)建/獲取共享內(nèi)存
int shmget(key_t key, size_t size, int shmflg);
參數(shù)說(shuō)明:
key_t key: 共享內(nèi)存鍵值IPC_PRIVATE: 創(chuàng)建私有共享內(nèi)存ftok()生成: 使用文件路徑和項(xiàng)目ID生成
- 自定義整數(shù)值: 如0x1234
size_t size: 共享內(nèi)存大小(字節(jié))int shmflg: 標(biāo)志和權(quán)限的組合IPC_CREAT: 如果不存在則創(chuàng)建IPC_EXCL: 與IPC_CREAT一起使用,如果已存在則失敗- 權(quán)限標(biāo)志:
0666,0600等(八進(jìn)制)
返回值:
- 成功: 共享內(nèi)存標(biāo)識(shí)符
- 失敗: -1,并設(shè)置errno
示例:
// 創(chuàng)建新的共享內(nèi)存 int shmid = shmget(0x1234, 1024, IPC_CREAT | 0666); // 獲取已存在的共享內(nèi)存 int shmid = shmget(0x1234, 0, 0666); // 創(chuàng)建私有共享內(nèi)存 int shmid = shmget(IPC_PRIVATE, 1024, 0666);
2.shmat()- 附加共享內(nèi)存
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數(shù)說(shuō)明:
int shmid: 共享內(nèi)存ID(shmget返回值)const void *shmaddr: 指定附加地址NULL: 系統(tǒng)自動(dòng)選擇地址(推薦)- 具體地址: 指定附加到哪個(gè)地址
int shmflg: 附加標(biāo)志SHM_RDONLY: 只讀方式附加0: 讀寫(xiě)方式附加
返回值:
- 成功: 共享內(nèi)存附加地址
- 失敗:
(void*)-1,并設(shè)置errno
示例:
// 讀寫(xiě)方式附加 char *shm_addr = shmat(shmid, NULL, 0); // 只讀方式附加 char *shm_addr = shmat(shmid, NULL, SHM_RDONLY);
3.shmdt()- 分離共享內(nèi)存
int shmdt(const void *shmaddr);
參數(shù)說(shuō)明:
const void *shmaddr: 共享內(nèi)存地址(shmat返回值)
返回值:
- 成功: 0
- 失敗: -1,并設(shè)置errno
示例:
shmdt(shm_addr);
4.shmctl()- 控制共享內(nèi)存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數(shù)說(shuō)明:
int shmid: 共享內(nèi)存IDint cmd: 控制命令IPC_STAT: 獲取狀態(tài)信息到bufIPC_SET: 設(shè)置共享內(nèi)存參數(shù)IPC_RMID: 標(biāo)記刪除共享內(nèi)存SHM_LOCK: 鎖定共享內(nèi)存(防止交換)SHM_UNLOCK: 解鎖共享內(nèi)存
struct shmid_ds *buf: 狀態(tài)信息緩沖區(qū)
返回值:
- 成功: 0
- 失敗: -1,并設(shè)置errno
示例:
// 刪除共享內(nèi)存 shmctl(shmid, IPC_RMID, NULL); // 獲取共享內(nèi)存信息 struct shmid_ds shm_info; shmctl(shmid, IPC_STAT, &shm_info);
5.ftok()- 生成IPC鍵值
key_t ftok(const char *pathname, int proj_id);
參數(shù)說(shuō)明:
const char *pathname: 存在的文件路徑int proj_id: 項(xiàng)目標(biāo)識(shí)符(0-255)
返回值:
- 成功: IPC鍵值
- 失敗: -1,并設(shè)置errno
示例:
key_t key = ftok("/tmp/myapp", 'A');編譯和運(yùn)行
編譯命令:
# 編譯所有文件 gcc -o writer writer.c shm_common.c gcc -o reader reader.c shm_common.c
運(yùn)行步驟:
先運(yùn)行寫(xiě)入進(jìn)程:
./writer
再運(yùn)行讀取進(jìn)程(新終端):
./reader
運(yùn)行結(jié)果示例:
=== 共享內(nèi)存寫(xiě)入進(jìn)程 ===
創(chuàng)建共享內(nèi)存成功, shmid = 98304
=== 共享內(nèi)存信息 ===
共享內(nèi)存ID: 98304
鍵值: 0x1234
大小: 1024 字節(jié)
創(chuàng)建者PID: 1234
最后操作PID: 0
附加進(jìn)程數(shù): 0
...
寫(xiě)入數(shù)據(jù): 這是第 1 條消息 - 時(shí)間戳: 1634567890
等待讀取進(jìn)程讀取數(shù)據(jù)...
注意事項(xiàng)
- 同步問(wèn)題:共享內(nèi)存需要額外的同步機(jī)制(信號(hào)量、互斥鎖等)
- 資源清理:確保進(jìn)程退出前分離共享內(nèi)存
- 權(quán)限設(shè)置:根據(jù)安全需求設(shè)置適當(dāng)?shù)臋?quán)限
- 錯(cuò)誤處理:檢查所有系統(tǒng)調(diào)用的返回值
- 內(nèi)存對(duì)齊:考慮數(shù)據(jù)結(jié)構(gòu)的內(nèi)存對(duì)齊問(wèn)題
到此這篇關(guān)于C語(yǔ)言中共享內(nèi)存完整示例示例的文章就介紹到這了,更多相關(guān)C語(yǔ)言 共享內(nèi)存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入分析C++中執(zhí)行多個(gè)exe文件方法的批處理代碼介紹
本篇文章是對(duì)C++中執(zhí)行多個(gè)exe文件方法的批處理代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
QT結(jié)合百度Ai實(shí)現(xiàn)車牌識(shí)別
當(dāng)下的人工智能勢(shì)頭很盛,本文主要介紹了QT結(jié)合百度Ai實(shí)現(xiàn)車牌識(shí)別,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
C++深入講解new與deleted關(guān)鍵字的使用
這篇文章主要介紹了C++中new與deleted關(guān)鍵字的使用,new在動(dòng)態(tài)內(nèi)存中為對(duì)象分配空間并返回一個(gè)指向該對(duì)象的指針;delete接受一個(gè)動(dòng)態(tài)對(duì)象的指針, 銷毀該對(duì)象, 并釋放與之關(guān)聯(lián)的內(nèi)存2022-05-05
基于Sizeof與Strlen的區(qū)別以及聯(lián)系的使用詳解
本篇文章是對(duì)Sizeof與Strlen的區(qū)別以及聯(lián)系的使用進(jìn)行了詳細(xì)的介紹。需要的朋友參考下2013-05-05
C++利用數(shù)組(一維/二維)處理批量數(shù)據(jù)的方法
對(duì)于簡(jiǎn)單的問(wèn)題,使用簡(jiǎn)單的數(shù)據(jù)類型就可以了,但是對(duì)于有些需要處理的數(shù)據(jù),只用以上簡(jiǎn)單的數(shù)據(jù)類型是不夠的,難以反映出數(shù)據(jù)的特點(diǎn),也難以有效的進(jìn)行處理,本文小編給大家介紹了C++利用數(shù)組(一維/二維)處理批量數(shù)據(jù)的方法,需要的朋友可以參考下2023-10-10
C++中結(jié)構(gòu)體和Json字符串互轉(zhuǎn)的問(wèn)題詳解
這篇文章主要給大家介紹了關(guān)于C++中結(jié)構(gòu)體和Json字符串互轉(zhuǎn)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Linux中使用VS Code編譯調(diào)試C++項(xiàng)目詳解
最近因?yàn)轫?xiàng)目的需求,需要在Linux下開(kāi)發(fā)C++相關(guān)項(xiàng)目,經(jīng)過(guò)一番摸索最終實(shí)現(xiàn)了,下面這篇文章就給大家簡(jiǎn)單總結(jié)了一下如何通過(guò)VS Code進(jìn)行編譯調(diào)試的一些注意事項(xiàng)。有需要的朋友們可以參考借鑒,下面來(lái)跟著小編一起看看吧。2016-12-12

