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

Linux內存映射:msync()與munmap()函數詳解

     編輯:關於C語言

msync() - 同步內存映射區數據到磁盤

函數原型

#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);

參數說明

  • addr:映射區起始地址(需頁對齊)
  • len:同步長度(字節)
  • flags:同步模式(位掩碼可組合)
    • MS_ASYNC:異步寫入,調用即返回,不等待寫入完成
    • MS_SYNC:同步寫入,阻塞直到數據寫入磁盤
    • MS_INVALIDATE:使其他映射同一文件的進程失效緩存,強制重新讀取最新數據

返回值與錯誤碼

  • 成功返回 0
  • 失敗返回 -1,errno 設置:
    • EBUSY:部分頁面被鎖定
    • EINVAL:參數無效(地址未對齊/長度為0/flags無效)
    • ENOMEM:地址範圍未映射

典型應用場景

  1. 數據持久化關鍵點:事務提交前調用 msync(addr, len, MS_SYNC) 確保數據落盤
  2. 多進程共享內存同步:寫入進程 MS_SYNC | MS_INVALIDATE,讀取進程自動看到最新數據
  3. 高性能日誌系統:異步寫入 MS_ASYNC 定期刷新,平衡性能與安全

munmap() - 解除內存映射

函數原型

#include <unistd.h>
#include <sys/mman.h>
int munmap(void *addr, size_t len);

參數說明

  • addr:映射區起始地址(必須是 mmap 返回的地址)
  • len:映射區長度(必須與 mmap 時一致)

行為特點

  • 解除進程虛擬地址空間中的映射關係
  • 隱式調用 msync(MS_SYNC):修改過的共享映射頁面會自動寫回文件
  • 進程退出或 exec 族函數調用時自動解除所有映射
  • 關閉文件描述符 不會 解除映射(映射建立後獨立於文件描述符)

返回值與錯誤

  • 成功返回 0
  • 失敗返回 -1,errno = EINVAL(地址/長度非法,如未頁對齊、超出映射範圍)

完整使用示例:進程間共享計數器

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main() {
    // 1. 打開/創建文件
    int fd = open("counter.dat", O_RDWR | O_CREAT, 0644);
    if (fd < 0) { perror("open"); return 1; }
    
    // 2. 設置文件大小
    ftruncate(fd, sizeof(int));
    
    // 3. 內存映射(共享映射,可讀寫)
    int* counter = (int*)mmap(NULL, sizeof(int), 
                              PROT_READ | PROT_WRITE, 
                              MAP_SHARED, fd, 0);
    if (counter == MAP_FAILED) { perror("mmap"); return 1; }
    
    close(fd);  // 映射後可關閉fd,不影響映射
    
    // 4. 父子進程測試
    pid_t pid = fork();
    if (pid == 0) {  // 子進程:增加計數
        for (int i = 0; i < 100000; i++) {
            (*counter)++;
            // 關鍵:定期同步,或依賴munmap/進程退出時自動同步
            if (i % 10000 == 0) msync(counter, sizeof(int), MS_SYNC);
        }
        munmap(counter, sizeof(int));
    } else {  // 父進程:讀取計數
        wait(NULL);  // 等待子進程結束
        printf("Final counter: %d\n", *counter);
        munmap(counter, sizeof(int));
    }
    return 0;
}

最佳實踐總結

場景推薦調用說明
高頻寫入、對性能敏感定期 msync(MS_ASYNC) + 退出前 MS_SYNC異步刷新減少阻塞,最終同步保證數據安全
多進程實時共享msync(MS_SYNC | MS_INVALIDATE)強制同步並通知其他進程緩存失效
只讀映射無需 msync只讀映射不修改數據,無同步必要
臨時映射(如文件讀取)用完即 munmap及時釋放虛擬地址空間,避免洩漏

注意事項

  1. 地址對齊:addr 必須是頁大小(通常4KB)整數倍,建議傳入 mmap 返回的原始地址
  2. 長度匹配:munmap 的 len 必須與 mmap 時一致,否則 EINVAL
  3. 並發安全:共享映射區的讀寫需配合信號量/互斥鎖/原子操作,msync 不提供同步互斥
  4. MAP_PRIVATE:私有映射修改不會寫回文件,msync 無效,munmap 只丟棄修改
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved