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:地址範圍未映射
典型應用場景
- 數據持久化關鍵點:事務提交前調用
msync(addr, len, MS_SYNC) 確保數據落盤
- 多進程共享內存同步:寫入進程
MS_SYNC | MS_INVALIDATE,讀取進程自動看到最新數據
- 高性能日誌系統:異步寫入
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 | 及時釋放虛擬地址空間,避免洩漏 |
注意事項
- 地址對齊:
addr 必須是頁大小(通常4KB)整數倍,建議傳入 mmap 返回的原始地址
- 長度匹配:
munmap 的 len 必須與 mmap 時一致,否則 EINVAL
- 並發安全:共享映射區的讀寫需配合信號量/互斥鎖/原子操作,
msync 不提供同步互斥
- MAP_PRIVATE:私有映射修改不會寫回文件,
msync 無效,munmap 只丟棄修改