You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:03:19