一、fcntl函數
功能:操縱文件描述符,改變已打開的文件的屬性
int fcntl(int fd, int cmd, ... /* arg */ );
cmd的取值可以如下:
復制文件描述符
F_DUPFD (long)
設置/獲取文件描述符標志
F_GETFD (void)
F_SETFD (long)
設置/獲取文件狀態標志
F_GETFL (void)
F_SETFL (long)
獲取/設置文件鎖
F_GETLK
F_SETLK,F_SETLKW
其中復制文件描述符可參見《 linux系統編程之文件與I/O(五):打開文件的內核結構file和重定向 》,文件描述符的標志只有一個即FD_CLOEXEC,設置/獲取文件描述符標志等學習到進程部分再說。下面先來看設置/獲取文件狀態標志。
F_SETFL:
On Linux ?this ?command?can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
示例程序如下:
?
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
? |
/*************************************************************************
????>?File?Name:?file_fcntl.c ????>?Author:?Simba ????>?Mail:?dameng34@163.com ????>?Created?Time:?Sat?23?Feb?2013?02:34:02?PM?CST ?************************************************************************/ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define ?ERR_EXIT(m)?\ ???? do ?{?\ ????????perror(m);?\ ????????exit(EXIT_FAILURE);?\ ????}? while ( 0 ) void ?set_flag( int ,? int ); void ?clr_flag( int ,? int ); int ?main( int ?argc,? char ?*argv[]) { ???? char ?buf[ 1024 ]?=?{ 0 }; ???? int ?ret; ???? /* ????????int?flags; ????????flags?=?fcntl(0,?F_GETFL,?0); ????????if?(flags?==?-1) ????????????ERR_EXIT("fcntl?get?flag?error"); ????????ret?=?fcntl(0,?SETFL,?flags?|?O_NONBLOCK);?//設置為非阻塞,但不更改其他狀態 ????????if?(ret?==?-1) ????????????ERR_EXIT("fcntl?set?flag?error"); ????*/ ????set_flag( 0 ,?O_NONBLOCK); ????ret?=?read( 0 ,?buf,? 1024 ); ???? if ?(ret?==?- 1 ) ????????ERR_EXIT( "read?error" ); ????printf( "buf=%s\n" ,?buf); ???? return ? 0 ; } void ?set_flag( int ?fd,? int ?flags) { ???? int ?val; ????val?=?fcntl(fd,?F_GETFL,? 0 ); ???? if ?(val?==?- 1 ) ????????ERR_EXIT( "fcntl?get?flag?error" ); ????val?|=?flags; ???? if ?(fcntl(fd,?F_SETFL,?val)?<? 0 ) ????????ERR_EXIT( "fcntl?set?flag?error" ); } void ?clr_flag( int ?fd,? int ?flags) { ???? int ?val; ????val?=?fcntl(fd,?F_GETFL,? 0 ); ???? if ?(val?==?- 1 ) ????????ERR_EXIT( "fcntl?get?flag?error" ); ????val?&=?~flags; ???? if ?(fcntl(fd,?F_SETFL,?val)?<? 0 ) ????????ERR_EXIT( "fcntl?set?flag?error" ); } |
測試輸出:
?
simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_fcntl?
read error: Resource temporarily unavailable
因為將標準輸入的狀態更改為非阻塞,則read不會阻塞等待輸入而立即返回錯誤,errno將被置為EAGAIN,即可以重新嘗試。
二、文件鎖結構體
struct flock {
...
short l_type; ? ? ? /* Type of lock: F_RDLCK,
? ? ? ? F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; ? ? ? /* Starting offset for lock */
off_t l_len; ? ? ? ? /* Number of bytes to lock */
pid_t l_pid; ? ? ? ?/* PID of process blocking our lock
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(F_GETLK only) */
? ? ?...
};
文件鎖的類型只有兩種,一種是寫鎖也叫排他鎖,一種是讀鎖也就共享鎖,可以有多個進程各持有一個讀鎖,但只能有一個進程持有寫鎖,只有對文件有對應的讀寫權限才能施加對應的鎖類型。中間三個參數 l_whence, ?l_start, l_len 決定了被鎖定的文件范圍。當fcntl 函數的cmd為F_GETLK時,flock 結構體的 l_pid 參數會返回持有某種類型鎖的進程id。進程退出或者文件描述符被關閉時,會釋放所有的鎖。
示例程序如下:
?
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
? |
/*************************************************************************
????>?File?Name:?file_flock.c ????>?Author:?Simba ????>?Mail:?dameng34@163.com ????>?Created?Time:?Sat?23?Feb?2013?02:34:02?PM?CST ?************************************************************************/ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define ?ERR_EXIT(m)?\ ???? do ?{?\ ????????perror(m);?\ ????????exit(EXIT_FAILURE);?\ ????}? while ( 0 ) int ?main( int ?argc,? char ?*argv[]) { ???? int ?fd; ????fd?=?open( "test2.txt" ,?O_CREAT?|?O_RDWR?|?O_TRUNC,? 0664 ); ???? if ?(fd?==?- 1 ) ????????ERR_EXIT( "open?error" ); ???? /*?只有對文件有相應的讀寫權限才能施加對應的文件鎖?*/ ???? struct ?flock?lock; ????memset(&lock,? 0 ,? sizeof (lock)); ????lock.l_type?=?F_WRLCK;? //?排他鎖,即不允許其他進程再對其加任何類型的鎖,但讀鎖(共享鎖)允許 ????lock.l_whence?=?SEEK_SET; ????lock.l_start?=? 0 ;? //從文件開頭開始鎖定 ????lock.l_len?=? 0 ;? //?文件全部內容鎖住 ???? if ?(fcntl(fd,?F_SETLK,?&lock)?==? 0 ) ????{ ???????? /*?若為F_SETLKW,這時如果鎖已經被其他進程占用,則此進程會阻塞直到其他進程釋放鎖*/ ????????printf( "lock?success\n" ); ????????printf( "press?any?key?to?unlock\n" ); ????????getchar(); ????????lock.l_type?=?F_UNLCK; ???????? if ?(fcntl(fd,?F_SETLK,?&lock)?==? 0 ) ????????????printf( "unlock?success\n" ); ???????? else ????????????ERR_EXIT( "unlock?fail" ); ????} ???? else ????????ERR_EXIT( "lock?fail" ); ???? return ? 0 ;? //進程退出會對所有文件解鎖 } |
?
?
測試如下:
我們先在一個 終端執行程序:
simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock?
lock success
press any key to unlock
現在文件已經被鎖住了,而且沒有按下任何按鍵,所以卡在這里,也還沒解鎖,接著在另一個終端再次執行同個程序:
simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock?
lock fail: Resource temporarily unavailable
會立即返回錯誤,因為我們希望施加的是排他鎖,而現在前面一個進程正在占用寫鎖還沒釋放,所以嘗試施加鎖失敗,而如果fcntl 函數的cmd 設置為 F_SETLKW,即帶w的版本,則此進程會一直阻塞直到前面一個進程釋放了鎖。
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
