當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > Open函數(shù)的flag和fcntl詳解
Open函數(shù)的flag和fcntl詳解
時間:2018-09-27 來源:未知
1:文件讀寫權(quán)限
Linux中文件有讀寫權(quán)限,我們在open打開文件時也可以附帶一定的權(quán)限說明。比如
O_RDLNLY就表示以只讀方式打開,O_WRONLY表示以只寫方式打開,O_RDWR表示以可讀可寫方式打開。當(dāng)我們在open文件時附帶了某種權(quán)限后,打開的文件就只能按照該權(quán)限來操作。
本文引用地址://www.dimor.cc/emb/Column/7285.html
2:更改文件內(nèi)容
當(dāng)我們open已經(jīng)存在并且內(nèi)部有內(nèi)容的文件會出現(xiàn)幾種情況,
2-1:原來內(nèi)容消失使用O_TRUNC標(biāo)志。
2-2:新內(nèi)容添加到原內(nèi)容后面使用O_APPEND標(biāo)志
3:退出進(jìn)程或程序
1:dang程序在前面的操作執(zhí)行失敗導(dǎo)致后面的操作都不可能進(jìn)行下去時,我們應(yīng)在前面的錯誤監(jiān)測程序中結(jié)束整個程序,不應(yīng)該讓程序繼續(xù)運行下去。
2:在main函數(shù)中使用return關(guān)鍵字,一般原則是程序正常終止return 0, 程序異常終止return -1,
3:正式終止程序應(yīng)使用exit或_exit,一般原則是進(jìn)程正常終止exit(0),程序異常終止exit(-1)。
4:阻塞與非阻塞
1:如果某個函數(shù)是阻塞的,則我們調(diào)用該函數(shù)時當(dāng)前進(jìn)程有可能被阻塞住(實質(zhì)是該函數(shù)內(nèi)部要完成的事情條件不具備,當(dāng)前沒法做,要等待條件成熟),函數(shù)被阻塞住了就不能立刻返回;如果某個函數(shù)是非阻塞的,那么我們調(diào)用這個函數(shù)后一定會立即返回,但是函數(shù)有沒有完成任務(wù)不一定。
(2)阻塞和非阻塞是兩種不同的設(shè)計思路,并沒有好壞;總的來說,阻塞式的結(jié)果有保障但是時間沒保障;非阻塞式的時間有保障但結(jié)果沒保障。
(3)操作系統(tǒng)提供的API和由API封裝而成的庫函數(shù),有很多本身就是被設(shè)計為阻塞式或者非阻塞式的,所以我們應(yīng)用程序調(diào)用這些函數(shù)的時必須明確該函數(shù)是阻塞式還是非阻塞式。
(4)默認(rèn)情況下,我們open某個文件時是阻塞式的(在打開該文件后讀寫該文件時若出現(xiàn)問題則會導(dǎo)致阻塞),如果希望以非阻塞的方式打開文件,則flag中要加O_NONBLOCK標(biāo)志;阻塞與非阻塞只作用于設(shè)備文件(linux的硬件設(shè)備如串口、I2C通訊器件、LCD),而不作用于普通文件。
功能描述:根據(jù)文件描述詞來操作文件的特性。
#include
#include
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
[描述]
fcntl()針對(文件)描述符提供控制。參數(shù)fd是被參數(shù)cmd操作(如下面的描述)的描述符。針對cmd的值,fcntl能夠接受第三個參數(shù)int arg。
[返回值]
fcntl()的返回值與命令有關(guān)。如果出錯,所有命令都返回-1,如果成功則返回某個其他值。下列三個命令有特定返回值:F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN。
F_DUPFD 返回新的文件描述符
F_GETFD 返回相應(yīng)標(biāo)志
F_GETFL , F_GETOWN 返回一個正的進(jìn)程ID或負(fù)的進(jìn)程組ID
fcntl函數(shù)有5種功能:
1. 復(fù)制一個現(xiàn)有的描述符(cmd=F_DUPFD).
2. 獲得/設(shè)置文件描述符標(biāo)記(cmd=F_GETFD或F_SETFD).
3. 獲得/設(shè)置文件狀態(tài)標(biāo)記(cmd=F_GETFL或F_SETFL).
4. 獲得/設(shè)置異步I/O所有權(quán)(cmd=F_GETOWN或F_SETOWN).
5. 獲得/設(shè)置記錄鎖(cmd=F_GETLK , F_SETLK或F_SETLKW).
1. cmd值的F_DUPFD :
F_DUPFD 返回一個如下描述的(文件)描述符:
● 小的大于或等于arg的一個可用的描述符
● 與原始操作符一樣的某對象的引用
● 如果對象是文件(file)的話,則返回一個新的描述符,這個描述符與arg共享相同的偏移量(offset)
● 相同的訪問模式(讀,寫或讀/寫)
● 相同的文件狀態(tài)標(biāo)志(如:兩個文件描述符共享相同的狀態(tài)標(biāo)志)
● 與新的文件描述符結(jié)合在一起的close-on-exec標(biāo)志被設(shè)置成交叉式訪問execve(2)的系統(tǒng)調(diào)用
實際上調(diào)用dup(oldfd);
等效于
fcntl(oldfd, F_DUPFD, 0);
而調(diào)用dup2(oldfd, newfd);
等效于
close(oldfd);
fcntl(oldfd, F_DUPFD, newfd);
2. cmd值的F_GETFD和F_SETFD:
F_GETFD 取得與文件描述符fd聯(lián)合的close-on-exec標(biāo)志,類似FD_CLOEXEC。如果返回值和FD_CLOEXEC進(jìn)行與運算結(jié)果是0的話,文件保持交叉式訪問exec(),否則如果通過exec運行的話,文件將被關(guān)閉(arg 被忽略)
F_SETFD 設(shè)置close-on-exec標(biāo)志,該標(biāo)志以參數(shù)arg的FD_CLOEXEC位決定,應(yīng)當(dāng)了解很多現(xiàn)存的涉及文件描述符標(biāo)志的程序并不使用常數(shù) FD_CLOEXEC,而是將此標(biāo)志設(shè)置為0(系統(tǒng)默認(rèn),在exec時不關(guān)閉)或1(在exec時關(guān)閉)
在修改文件描述符標(biāo)志或文件狀態(tài)標(biāo)志時必須謹(jǐn)慎,先要取得現(xiàn)在的標(biāo)志值,然后按照希望修改它,后設(shè)置新標(biāo)志值。不能只是執(zhí)行F_SETFD或F_SETFL命令,這樣會關(guān)閉以前設(shè)置的標(biāo)志位。
3. cmd值的F_GETFL和F_SETFL:
F_GETFL 取得fd的文件狀態(tài)標(biāo)志,如同下面的描述一樣(arg被忽略),在說明open函數(shù)時,已說明
了文件狀態(tài)標(biāo)志。不幸的是,三個存取方式標(biāo)志 (O_RDONLY , O_WRONLY , 以及O_RDWR)并不各占1位。(這三種標(biāo)志的值各是0 , 1和2,由于歷史原因,這三種值互斥 — 一個文件只能有這三種值之一。) 因此首先必須用屏蔽字O_ACCMODE相與取得存取方式位,然后將結(jié)果與這三種值相比較。
F_SETFL 設(shè)置給arg描述符狀態(tài)標(biāo)志,可以更改的幾個標(biāo)志是:O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC。而fcntl的文件狀態(tài)標(biāo)志總共有7個:O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC
可更改的幾個標(biāo)志如下面的描述:
O_NONBLOCK 非阻塞I/O,如果read(2)調(diào)用沒有可讀取的數(shù)據(jù),或者如果write(2)操作將阻塞,則read或write調(diào)用將返回-1和EAGAIN錯誤
O_APPEND 強制每次寫(write)操作都添加在文件大的末尾,相當(dāng)于open(2)的O_APPEND標(biāo)志
O_DIRECT 小化或去掉reading和writing的緩存影響。系統(tǒng)將企圖避免緩存你的讀或?qū)懙臄?shù)據(jù)。如果不能夠避免緩存,那么它將小化已經(jīng)被緩存了的數(shù)據(jù)造成的影響。如果這個標(biāo)志用的不夠好,將大大的降低性能
O_ASYNC 當(dāng)I/O可用的時候,允許SIGIO信號發(fā)送到進(jìn)程組,例如:當(dāng)有數(shù)據(jù)可以讀的時候
4. cmd值的F_GETOWN和F_SETOWN: 【Linux公社 //www.linuxidc.com 】
F_GETOWN 取得當(dāng)前正在接收SIGIO或者SIGURG信號的進(jìn)程id或進(jìn)程組id,進(jìn)程組id返回的是負(fù)值(arg被忽略)
F_SETOWN 設(shè)置將接收SIGIO和SIGURG信號的進(jìn)程id或進(jìn)程組id,進(jìn)程組id通過提供負(fù)值的arg來說明(arg絕對值的一個進(jìn)程組ID),否則arg將被認(rèn)為是進(jìn)程id
5. cmd值的F_GETLK, F_SETLK或F_SETLKW: 獲得/設(shè)置記錄鎖的功能,成功則返回0,若有錯誤則返回-1,錯誤原因存于errno。
F_GETLK 通過第三個參數(shù)arg(一個指向flock的結(jié)構(gòu)體)取得第一個阻塞lock description指向的鎖。取得的信息將覆蓋傳到fcntl()的flock結(jié)構(gòu)的信息。如果沒有發(fā)現(xiàn)能夠阻止本次鎖(flock)生成的鎖,這個結(jié)構(gòu)將不被改變,除非鎖的類型被設(shè)置成F_UNLCK
F_SETLK 按照指向結(jié)構(gòu)體flock的指針的第三個參數(shù)arg所描述的鎖的信息設(shè)置或者清除一個文件的segment鎖。F_SETLK被用來實現(xiàn)共享(或讀)鎖(F_RDLCK)或獨占(寫)鎖(F_WRLCK),同樣可以去掉這兩種鎖(F_UNLCK)。如果共享鎖或獨占鎖不能被設(shè)置,fcntl()將立即返回EAGAIN
F_SETLKW 除了共享鎖或獨占鎖被其他的鎖阻塞這種情況外,這個命令和F_SETLK是一樣的。如果共享鎖或獨占鎖被其他的鎖阻塞,進(jìn)程將等待直到這個請求能夠完成。當(dāng)fcntl()正在等待文件的某個區(qū)域的時候捕捉到一個信號,如果這個信號沒有被指定SA_RESTART, fcntl將被中斷
當(dāng)一個共享鎖被set到一個文件的某段的時候,其他的進(jìn)程可以set共享鎖到這個段或這個段的一部分。共享鎖阻止任何其他進(jìn)程set獨占鎖到這段保護(hù)區(qū)域的任何部分。如果文件描述符沒有以讀的訪問方式打開的話,共享鎖的設(shè)置請求會失敗。
獨占鎖阻止任何其他的進(jìn)程在這段保護(hù)區(qū)域任何位置設(shè)置共享鎖或獨占鎖。如果文件描述符不是以寫的訪問方式打開的話,獨占鎖的請求會失敗。
結(jié)構(gòu)體flock的指針:
struct flcok
{
short int l_type; /* 鎖定的狀態(tài)*/
//以下的三個參數(shù)用于分段對文件加鎖,若對整個文件加鎖,則:l_whence=SEEK_SET, l_start=0, l_len=0
short int l_whence; /*決定l_start位置*/
off_t l_start; /*鎖定區(qū)域的開頭位置*/
off_t l_len; /*鎖定區(qū)域的大小*/
pid_t l_pid; /*鎖定動作的進(jìn)程*/
};
l_type 有三種狀態(tài):
F_RDLCK 建立一個供讀取用的鎖定
F_WRLCK 建立一個供寫入用的鎖定
F_UNLCK 刪除之前建立的鎖定
l_whence 也有三種方式:
SEEK_SET 以文件開頭為鎖定的起始位置
SEEK_CUR 以目前文件讀寫位置為鎖定的起始位置
SEEK_END 以文件結(jié)尾為鎖定的起始位置
fcntl文件鎖有兩種類型:建議性鎖和強制性鎖
建議性鎖是這樣規(guī)定的:每個使用上鎖文件的進(jìn)程都要檢查是否有鎖存在,當(dāng)然還得尊重已有的鎖。內(nèi)核和系統(tǒng)總體上都堅持不使用建議性鎖,它們依靠程序員遵守這個規(guī)定。
強制性鎖是由內(nèi)核執(zhí)行的:當(dāng)文件被上鎖來進(jìn)行寫入操作時,在鎖定該文件的進(jìn)程釋放該鎖之前,內(nèi)核會阻止任何對該文件的讀或?qū)懺L問,每次讀或?qū)懺L問都得檢查鎖是否存在。

