首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 實作檔案變更監控與信號驅動通知機制

     編輯:關於C++

核心思路:信號 + 非阻塞輪詢 = 高效檔案監控

本文示範如何在 Linux/Unix 環境下,結合 SIGINT 信號處理與 sigprocmask/sigsuspend 原語,實作一個輕量級的檔案大小變更監控器。核心邏輯:

  1. 註冊信號處理器,將全域旗標 sigflag 翻轉
  2. 主迴圈中 阻塞信號 → 檢查旗標 → 暫停等待信號 → 恢復信號遮罩
  3. 喚醒後立即 stat() 比對檔案大小,若異則報警

關鍵代碼解析

1. 信號處理器與初始化

static volatile sig_atomic_t sigflag = 0;

static void TurnFlag(int signo) {
    sigflag = (sigflag == 0) ? 1 : 0;   // 翻轉旗標
}

int InitHandler(int signo) {
    struct sigaction act = {0};
    act.sa_handler = TurnFlag;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, signo);
    return sigaction(signo, &act, NULL);
}

重點:sig_atomic_t 保證原子讀寫;sa_mask 在處理器執行期間自動阻塞同一信號,防止重入。

2. 信號控制核心:ControlSig()

int ControlSig(int signo) {
    sigset_t unblock, block, oldmask;

    sigprocmask(SIG_SETMASK, NULL, &unblock);  // 取得目前遮罩
    block = unblock;
    sigaddset(&block, signo);                  // 欲阻塞的信號
    sigdelset(&unblock, signo);                // 欲解除阻塞的集合

    sigprocmask(SIG_BLOCK, &block, &oldmask);  // 阻塞信號、保存舊遮罩

    while (sigflag != 0)                       // 旗標已置位 → 處理完畢前持續等待
        sigsuspend(&unblock);                  // 原子性:解除阻塞並休眠

    sigprocmask(SIG_SETMASK, &oldmask, NULL);  // 還原遮罩
    return 0;
}

設計精華:sigsuspend() 原子地「切換遮罩 + 睡眠」,避免 sigprocmask() + pause() 之間的競態條件。

3. 測試主程式:監控 Makefile 大小變化

int main() {
    struct stat oldst, newst;
    const char *path = "makefile";
    const int interval = 2;
    int signo = SIGINT;

    stat(path, &oldst);

    for (;;) {
        InitHandler(signo);
        ControlSig(signo);                     // 等待信號觸發

        stat(path, &newst);
        if (newst.st_size != oldst.st_size) {
            oldst.st_size = newst.st_size;
            fprintf(stderr, "檔案大小已變更!目前大小:%ld\n", newst.st_size);
        }
        sleep(interval);
    }
}

進階擴充建議

  • 換用 inotify/fanotify:Linux 核心級事件通知,無需輪詢,延遲更低。
  • 支援多檔案:結合 epoll 監控多個 inotify_fd。
  • 跨平台封裝:Windows 可用 ReadDirectoryChangesW,macOS 採 FSEvents,統一抽象介面。
  • 持久化記錄:整合 spdlog/spdlog 落地審計日誌。

常見坑點提醒

  1. sigflag 必須宣告為 volatile sig_atomic_t,否則編譯器優化可能導致主迴圈看不到更新。
  2. sigsuspend() 的遮罩參數是「臨時解除阻塞的集合」,而非「要阻塞的集合」——初學者最易搞反。
  3. 信號處理器中嚴禁呼叫非 async-signal-safe 函式(如 printf、malloc、fprintf),本例僅翻轉旗標屬安全操作。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved