Linux系統程式設計(3)——檔案與IO之fcntl函式
linux檔案I/O用:open、read、write、lseek以及close函式實現了檔案的開啟、讀寫等基本操作。fcntl函式可以根據檔案描述詞來操作檔案。
用法:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock*lock);
引數:
fd:檔案描述詞。
cmd:操作命令。
arg:供命令使用的引數。
lock:同上。
有以下操作命令可供使用
1. F_DUPFD :複製檔案描述詞 。
2. FD_CLOEXEC :設定close-on-exec標誌。如果FD_CLOEXEC位是0,執行execve的過程中,檔案保持開啟。反之則關閉。
3. F_GETFD :讀取檔案描述詞標誌。
4. F_SETFD :設定檔案描述詞標誌。
5. F_GETFL :讀取檔案狀態標誌。
6. F_SETFL :設定檔案狀態標誌。
其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY 和 O_TRUNC不受影響,
可以更改的標誌有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。
7. F_GETLK, F_SETLK 和 F_SETLKW :獲取,釋放或測試記錄鎖,使用到的引數是以下結構體指標:
F_SETLK:在指定的位元組範圍獲取鎖(F_RDLCK,F_WRLCK)或者釋放鎖(F_UNLCK)。如果與另一個程式的鎖操作發生衝突,返回 -1並將errno設定為EACCES或EAGAIN。
F_SETLKW:行為如同F_SETLK,除了不能獲取鎖時會睡眠等待外。如果在等待的過程中接收到訊號,會立即返回並將errno置為EINTR。
F_GETLK:獲取檔案鎖資訊。
F_UNLCK:釋放檔案鎖。
為了設定讀鎖,檔案必須以讀的方式開啟。為了設定寫鎖,檔案必須以寫的方式開啟。為了設定讀寫鎖,檔案必須以讀寫的方式開啟。
8. 訊號管理
F_GETOWN, F_SETOWN, F_GETSIG 和 F_SETSIG 被用於IO可獲取的訊號。
F_GETOWN:獲取當前在檔案描述詞 fd上接收到SIGIO 或 SIGURG事件訊號的程式或程式組標識 。
F_SETOWN:設定將要在檔案描述詞fd上接收SIGIO 或 SIGURG事件訊號的程式或程式組標識 。
F_GETSIG:獲取標識輸入輸出可進行的訊號。
F_SETSIG:設定標識輸入輸出可進行的訊號。
使用以上命令,大部分時間程式無須使用select()或poll()即可實現完整的非同步I/O。
9. 租約( Leases)
F_SETLEASE 和 F_GETLEASE 被用於當前程式在檔案上的租約。檔案租約提供當一個程式試圖開啟或折斷檔案內容時,擁有檔案租約的程式將會被通告的機制。
F_SETLEASE:根據以下符號值設定或者刪除檔案租約
- F_RDLCK設定讀租約,當檔案由另一個程式以寫的方式開啟或折斷內容時,擁有租約的當前程式會被通告。
- F_WRLCK設定寫租約,當檔案由另一個程式以讀或以寫的方式開啟或折斷內容時,擁有租約的當前程式會被通告。
- F_UNLCK刪除檔案租約。
- F_GETLEASE:獲取租約型別。
10.檔案或目錄改變通告
(linux 2.4以上)當fd索引的目錄或目錄中所包含的某一檔案發生變化時,將會向程式發出通告。arg引數指定的通告事件有以下,兩個或多個值可以通過或運算組合。
1.DN_ACCESS 檔案被訪問 (read, pread,readv)
2.DN_MODIFY 檔案被修改(write,pwrite,writev, truncate, ftruncate)
3.DN_CREATE 檔案被建立(open, creat,mknod, mkdir, link, symlink, rename)
4.DN_DELETE 檔案被刪除(unlink, rmdir)
5.DN_RENAME 檔案被重新命名(rename)
6.DN_ATTRIB 檔案屬性被改變(chown, chmod,utime[s])
返回說明:
成功執行時,對於不同的操作,有不同的返回值
F_DUPFD: 新檔案描述詞
F_GETFD: 標誌值
F_GETFL: 標誌值
F_GETOWN: 檔案描述詞屬主
F_GETSIG: 讀寫變得可行時將要傳送的通告訊號,或者0對於傳統的SIGIO行為
對於其它命令返回0。
失敗返回-1,errno被設為以下的某個值
EACCES/EAGAIN: 操作不被允許,尚未可行
EBADF: 檔案描述詞無效
EDEADLK: 探測到可能會發生死鎖
EFAULT: 鎖操作發生在可訪問的地址空間外
EINTR: 操作被訊號中斷
EINVAL: 引數無效
EMFILE: 程式已超出檔案的最大可使用範圍
ENOLCK: 鎖已被用盡
EPERM:權能不允許
在檔案已經共享的情況下如何操作,也就是當多個使用者共同使用、操作一個檔案時,Linux 通常採用的方法是給檔案上鎖,來避免共享的資源產生競爭的狀態。
檔案鎖包括建議性鎖和強制性鎖。
建議性鎖要求每個上鎖檔案的程式都要檢查是否有鎖存,並且尊重已有的鎖。在一般情況下,核心和系統都不使用建議性鎖。強制性鎖是由核心執行的鎖,當一個檔案被上鎖進行寫入操作的時候,核心將阻止其他任何檔案對其進行讀寫操作。採用強制性鎖對效能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。
在 Linux 中,實現檔案上鎖的函式有lock和fcntl,其中flock用於對檔案施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強制鎖。同時,fcntl還能對檔案的某一記錄進行上鎖,也就是記錄鎖。
記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個程式都能在檔案的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個程式在檔案的某個部分上建立寫入鎖。當然,在檔案的同一部分不能同時建立讀取鎖和寫入鎖。
注意:
fcntl是一個非常通用的函式,它還可以改變檔案程式各方面的屬性,在本節中,主要介紹它建立記錄鎖的方法,關於它其他使用者感興趣的讀者可以參看fcntl手冊。
下面首先給出了使用fcntl 函式的檔案記錄鎖函式。在該函式中,首先給flock 結構體的對應位賦予相應的值。接著使用兩次fcntl函式分別用於給相關檔案上鎖和判斷檔案是否可以上鎖,這裡用到的cmd值分別為F_SETLK 和F_GETLK。
這個函式的原始碼如下所示:
/*lock_set函式*/
void lock_set(int fd, int type)
{
struct flock lock;
lock.l_whence = SEEK_SET;//賦值lock結構體
lock.l_start = 0;
lock.l_len =0;
while(1){
lock.l_type = type;
/*根據不同的type值給檔案上鎖或解鎖*/
if((fcntl(fd, F_SETLK, &lock)) == 0){
if( lock.l_type == F_RDLCK )
printf("read lock set by%d\n",getpid());
else if( lock.l_type == F_WRLCK )
printf("write lock set by%d\n",getpid());
else if( lock.l_type == F_UNLCK )
printf("release lock by%d\n",getpid());
return;
}
/*判斷檔案是否可以上鎖*/
fcntl(fd, F_GETLK,&lock);
/*判斷檔案不能上鎖的原因*/
if(lock.l_type != F_UNLCK){
/*/該檔案已有寫入鎖*/
if( lock.l_type == F_RDLCK )
printf("read lock already set by%d\n",lock.l_pid);
/*該檔案已有讀取鎖*/
else if( lock.l_type == F_WRLCK )
printf("write lock already set by%d\n",lock.l_pid);
getchar();
}
}
}
下面的例項是測試檔案的寫入鎖,這裡首先建立了一個hello檔案,之後對其上寫入鎖,最後釋放寫入鎖。程式碼如下所示:
/*fcntl_write.c測試檔案寫入鎖主函式部分*/
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
/*首先開啟檔案*/
fd=open("hello",O_RDWR | O_CREAT,0666);
if(fd < 0){
perror("open");
exit(1);
}
/*給檔案上寫入鎖*/
lock_set(fd, F_WRLCK);
getchar();
/*給檔案接鎖*/
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}
接下來的程式是測試檔案的讀取鎖,原理同上面的程式一樣。
/*fcntl_read.c測試檔案讀取鎖主函式部分*/
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
fd=open("hello",O_RDWR | O_CREAT,0666);
if(fd < 0){
perror("open");
exit(1);
}
/*給檔案上讀取鎖*/
lock_set(fd, F_RDLCK);
getchar();
/*給檔案接鎖*/
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}
相關文章
- Linux系統程式設計(4)——檔案與IO之ioctl函式Linux程式設計函式
- linux系統程式設計之檔案與IO(七):時間函式小結Linux程式設計函式
- Linux系統程式設計(2)——檔案與IO之系統呼叫與檔案IO操作Linux程式設計
- linux系統程式設計之檔案與IO(八):檔案描述符相關操作-dup,dup2,fcntlLinux程式設計
- Linux系統程式設計之檔案IOLinux程式設計
- Linux系統程式設計-檔案IOLinux程式設計
- linux系統程式設計之檔案與IO(三):利用lseek()建立空洞檔案Linux程式設計
- linux系統程式設計之檔案與IO(五):stat()系統呼叫獲取檔案資訊Linux程式設計
- linux系統程式設計之檔案與IO(一):檔案描述符、open,closeLinux程式設計
- linux系統程式設計之檔案與IO(二):系統呼叫read和writeLinux程式設計
- linux系統程式設計之檔案與IO(六):實現ls -l功能Linux程式設計
- 檔案鎖fcntl()函式的使用函式
- linux系統程式設計之檔案與IO(四):目錄訪問相關係統呼叫Linux程式設計
- Linux系統程式設計(9)—— 程式之程式控制函式exec系列函式Linux程式設計函式
- linux系統程式設計之程式(七):system()函式使用Linux程式設計函式
- Linux系統程式設計(8)—— 程式之程式控制函式forkLinux程式設計函式
- Linux系統程式設計之程式替換:exec 函式族Linux程式設計函式
- Linux系統程式設計【4】——檔案系統Linux程式設計
- linux程式設計之pipe()函式Linux程式設計函式
- linux系統程式設計之程式(一):程式與程式Linux程式設計
- linux系統程式設計之訊號(四):alarm和可重入函式Linux程式設計函式
- linux系統程式設計:setjmp和longjmp函式用法Linux程式設計函式
- 分散式檔案系統(HDFS)與 linux系統檔案系統 對比分散式Linux
- linux系統程式設計之程式(四):程式退出exit,_exit區別即atexit函式Linux程式設計函式
- linux系統程式設計之程式(五):exec系列函式(execl,execlp,execle,execv,execvp)使用Linux程式設計函式
- Linux系統程式設計(七)檔案許可權系統呼叫Linux程式設計
- Linux核心模組程式設計/proc 檔案系統(轉)Linux程式設計
- linux系統程式設計之訊號(五):訊號集操作函式,訊號阻塞與未決Linux程式設計函式
- (3)Linux效能調優之Linux檔案系統Linux
- Linux/Unix C程式設計之的perror函式,strerror函式,errnoLinuxC程式程式設計Error函式
- fcntl函式實現dup函式
- fcntl函式用法詳解函式
- Linux網路程式設計之IO模型Linux程式設計模型
- Linux系統程式設計之程式介紹Linux程式設計
- python程式設計之slice與indices函式用法Python程式設計函式
- 03 shell程式設計之case語句與函式程式設計函式
- 第七篇:使用 fcntl 函式 獲取,設定檔案的狀態標誌函式
- JavaScript函數語言程式設計之pointfree與宣告式程式設計JavaScript函數程式設計