Linux多进程系统中共享内存段最后修改时间检测方案问询
Linux共享内存写入检测的高效方案
核心问题明确
Linux下调用stat()获取的st_mtime不会随共享内存映射段的写入更新,全量哈希计算开销过高,需要一种轻量、无需知晓内存布局的检测方式。
推荐实现方案
1. inotify + fsync 组合监控
Linux的inotify可监控文件系统事件,但直接监控共享内存虚拟文件时,写入映射段不会触发IN_MODIFY,可通过以下方式规避:
- 主进程在映射共享内存的同时,保留该虚拟文件的读写句柄
- 每次写入共享内存后,主进程调用
fsync()刷新句柄(tmpfs下无需实际刷盘,仅更新文件元数据) - 看门狗通过
inotify监控IN_ATTRIB事件,或定期stat()查看st_ctime(fsync()会更新该字段)
Python看门狗代码示例:
import inotify.adapters import os import time WATCH_PATH = "/dev/shm/my_shm_segment" TIMEOUT = 10 # 超时时间(秒) def watch_shm(): i = inotify.adapters.Inotify() i.add_watch(WATCH_PATH, mask=inotify.constants.IN_ATTRIB) last_update = time.time() while True: for event in i.event_gen(yield_nones=False): _, mask, _, _ = event if mask & inotify.constants.IN_ATTRIB: last_update = time.time() print("共享内存已更新") # 超时检查 if time.time() - last_update > TIMEOUT: print(f"共享内存超时{TIMEOUT}秒未更新") # 执行看门狗动作(如重启进程) time.sleep(1) if __name__ == "__main__": watch_shm()
主进程写入后需执行的代码:
import os shm_fd = os.open("/dev/shm/my_shm_segment", os.O_RDWR) # 写入共享内存映射段的逻辑... os.fsync(shm_fd) # 触发元数据更新
2. 共享内存头部计数器(低开销方案)
在共享内存头部预留8字节的计数器,无需知晓其他内存布局:
- 主进程每次写入共享内存时,递增该计数器
- 看门狗映射共享内存,读取计数器并与上次值对比,判断是否有写入操作
- 内存级操作开销极低,实时性强
C++看门狗代码片段:
#include <sys/ipc.h> #include <sys/shm.h> #include <cstdint> #include <iostream> #include <chrono> #define SHM_KEY 0x123456 #define TIMEOUT_SEC 10 struct ShmHeader { uint64_t write_counter; // 其他业务数据... }; int main() { int shmid = shmget(SHM_KEY, sizeof(ShmHeader), 0666); if (shmid == -1) { perror("shmget failed"); return 1; } ShmHeader* shm_ptr = static_cast<ShmHeader*>(shmat(shmid, nullptr, 0)); if (shm_ptr == reinterpret_cast<void*>(-1)) { perror("shmat failed"); return 1; } uint64_t last_counter = shm_ptr->write_counter; auto last_update_time = std::chrono::steady_clock::now(); while (true) { uint64_t current_counter = shm_ptr->write_counter; if (current_counter != last_counter) { last_counter = current_counter; last_update_time = std::chrono::steady_clock::now(); std::cout << "共享内存已更新" << std::endl; } auto elapsed = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::steady_clock::now() - last_update_time ).count(); if (elapsed > TIMEOUT_SEC) { std::cout << "共享内存超时未更新" << std::endl; // 执行看门狗动作 } sleep(1); } shmdt(shm_ptr); return 0; }
主进程写入时只需执行:
shm_ptr->write_counter++;
3. eBPF无侵入追踪(进阶方案)
如果无法修改主进程代码,可利用eBPF追踪共享内存页的写入事件:
- 基于Linux内核4.15+版本,需要root权限
- 通过
bcc等Python库追踪do_page_fault或copy_to_user等内核函数,过滤目标共享内存的写入操作 - 完全无侵入,但实现复杂度较高
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| inotify + fsync | 无需修改共享内存布局,看门狗逻辑简单 | 需要主进程配合调用fsync |
| 共享内存计数器 | 开销极低,实时性好 | 需要预留计数器空间,主进程需配合更新 |
| eBPF追踪 | 完全无侵入,无需主进程修改 | 需要内核支持,权限要求高,实现复杂 |
内容的提问来源于stack exchange,提问作者Young_Maker
相关产品推荐
相关产品推荐

