關於檔案描述符的close-on-exec標誌位
引言
我們在使用一些系統呼叫對檔案描述符進行操作時,常常會碰到是否為檔案描述符賦予CLOEXEC屬性的情況,例如:
// open函式中的flags引數可指定O_CLOEXEC標誌
int open(const char *pathname, int flags);
// fcntl函式可通過FD_GETFD、FD_SETFD操作設定FD_CLOEXEC標誌
int fcntl(int fd, int cmd, ... /* arg */);
在上篇部落格,我們新學到的系統呼叫eventfd同樣也有:
// 引數flags可取EFD_NONBLOCK、EFD_CLOEXEC、EFD_SEMAPHORE
int eventfd(unsigned int initval, int flags);
那麼,close-on-exec標誌位究竟有什麼用呢?
設定close-on-exec標誌位的意義
close-on-exec字面意思即執行時關閉。程式中每個開啟的描述符都有一個執行時關閉標誌,若設定此標誌,則在執行exec時關閉該描述符,否則該描述符仍開啟。
設定該標誌位的重要意義在於它可以方便我們關閉無用的檔案描述符。
我們考慮這樣的情況:父程式fork出一個子程式,子程式是父程式的副本,獲得父程式的資料空間、堆和棧的副本,當然也包括父程式開啟的檔案描述符。
fork之後一般我們會呼叫exec執行另一個程式,此時會用全新的程式替換子程式的正文、資料、堆和棧等,此時儲存檔案描述符的變數當然也不存在了,我們就無法關閉無用的檔案描述符了。所以通常我們會在fork子程式後,在子程式中直接執行close關掉無用的檔案描述符,然後再執行exec。
但是在複雜系統中,有時我們fork出子程式時已經不知道開啟了多少檔案描述符了(包括socket控制程式碼等),如果進行逐一清理難度很大。我們期望的是能在fork出子程式前、開啟某個檔案描述符時就指定好——這個檔案描述符在我fork出子程式後、執行exec時就關閉。其實是有這樣的方法的:即所謂的 close-on-exec。
測試程式碼
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
int fd;
pid_t pid;
// 判斷是否定義_O_CLOEXEC巨集
#ifdef _O_CLOEXEC
if ((fd = open("my.txt", O_RDWR | O_CREAT | O_CLOEXEC, 0600)) < 0)
#else
if ((fd = open("my.txt", O_RDWR | O_CREAT, 0600)) < 0)
#endif
perror("open");
// 通過開啟-D_O_CLOEXEC -D_FORK編譯選項測試使用O_CLOEXEC模式的描述符在子程式中的狀態
#ifndef _FORK
// 執行execl後程式名更改為sleep
if (execl("/bin/sleep", "sleep", "10000", (void*)0) < 0)
perror("execl");
#else
switch ((pid = fork())) {
case -1:
perror("fork");
case 0:
if (execl("/bin/sleep", "sleep", "10000", (void*)0) < 0)
perror("execl");
default:
sleep(10000);
break;
}
#endif
return 0;
}
測試結果:
1.(1)編譯進O_CLOEXEC選項
程式資源中沒有了my.txt
(2)不編譯進O_CLOEXEC選項
程式資源中仍有my.txt
2.編譯進O_CLOEXEC選項、_FORK選項
子程式資源中沒有了my.txt,父程式中仍存在。
參考資料:
http://blog.csdn.net/chrisniu1984/article/details/7050663
http://blog.csdn.net/ubuntu_hao/article/details/51393632
相關文章
- Linux--檔案描述符、檔案指標、索引節點Linux指標索引
- 關於C++的標頭檔案C++
- 檔案描述符
- C語言關於標頭檔案的使用C語言
- linux中的檔案描述符Linux
- Linux檔案描述符Linux
- 檔案描述符和檔案系統
- 關於QT的標頭檔案相互包含的問題QT
- 檔案包含之包含了Linux檔案描述符Linux
- 12C關於CDB、PDB 日誌檔案redo log的總結
- 關於檔案的open方法
- c++ string 識別標誌位並解析標誌位後面的字元C++字元
- nginx的檔案描述符的學習之二Nginx
- windows 檔案描述符 _open_osfhandleWindows
- mysqlbinlog 處理二進位制日誌檔案的工具MySql
- mysql關於ibdata檔案的理解MySql
- 如何將日誌檔案和二進位制檔案快速匯入HDFS?
- HiveServer2 檔案描述符洩漏HiveServer
- mysql關於二進位制日誌binary log的總結MySql
- /etc/shadow檔案相關欄位的解釋
- sqlserver關於filestream檔案流、filetable檔案表的總結SQLServer
- 關於ubuntu修改hosts檔案的方法Ubuntu
- Android 關於 so 檔案的總結Android
- 關於Play框架的靜態檔案框架
- ABL讀取XBL設定的標誌位
- go開發屬於自己的日誌庫-檔案日誌庫實現Go
- python 關於描述符/property偽裝/協程Python
- 關於專案提案書/競標書的心得
- 基於Docker應用容器日誌檔案收集Docker
- go 開發屬於自己的日誌庫-檔案日誌庫原型實現Go原型
- 關於檔案系統在建立目錄檔案和普通檔案時的區別
- 一文幫你搞懂 Android 檔案描述符Android
- Linux 檔案系統與日誌分析的相關知識Linux
- 關於Java使用MinIO檔案伺服器操作檔案Java伺服器
- 2.6.1 關於初始化檔案
- 關於投標保證金,招標檔案中可以不要求嗎?有硬性規定嗎
- mysql關於db.opt檔案的總結MySql
- Golang - 關於 proto 檔案的一點小思考Golang
- mysql關於ib_logfile事務日誌和binary log二進位制日誌的區別MySql