linux基礎(chǔ)復(fù)習(xí)(6)文件I/O操作
上鎖,也就是記錄鎖。記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個進程都能在
文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個進程在文件的某個部分上建立寫入鎖。當(dāng)然,在文件的同一部分不能同時建立讀取鎖和寫入鎖。
fcntl函數(shù)格式
fcntl函數(shù)可以改變已經(jīng)打開文件的性質(zhì)。
#i nclude
#i nclude
#i nclude
int fcntl(int filedes, int cmd, ... ) ;
返回:若成功則依賴于cmd(見下),若出錯為- 1。
f c n t l函數(shù)有五種功能:
n 復(fù)制一個現(xiàn)存的描述符, 新文件描述符作為函數(shù)值返(c m d=F_DUPFD)。
n 獲得/設(shè)置文件描述符標(biāo)記,對應(yīng)于filedes 的文件描述符標(biāo)志作為函數(shù)值返回.(c m d = F_GETFD或F_SETFD)。
n 獲得/設(shè)置文件狀態(tài)標(biāo)志,對應(yīng)于filedes 的文件狀態(tài)標(biāo)志作為函數(shù)值返回。(c m d = F_GETFL或F_SETFL)。
n 獲得/設(shè)置異步I / O有權(quán)(c m d = F_GETOWN或F_SETOWN)。
n 獲得/設(shè)置記錄鎖(c m d = F_SETLK , F_SETLKW)。
關(guān)于加鎖和解鎖區(qū)域的說明還要注意下列各點:
l 該區(qū)域可以在當(dāng)前文件尾端處開始或越過其尾端處開始,但是不能在文件起始位置之前開始或越過該起始位置。
l 如若l_len為0,則表示鎖的區(qū)域從其起點(由l_start和l_whence決定)開始直至最大可能位置為止。也就是不管添寫到該文件中多少數(shù)據(jù),它都處于鎖的范圍。
l 為了鎖整個文件,通常的方法是將l_start說明為0,l_whence說明為SEEK_SET,l_len說明為0。
實例:
/*fcntl_write.c測試文件寫入鎖主函數(shù)部分*/
#i nclude unistd.h>
#i nclude sys/file.h>
#i nclude sys/types.h>
#i nclude sys/stat.h>
#i nclude stdio.h>
#i nclude stdlib.h>
/*lock_set函數(shù)*/
void lock_set(int fd, int type)
{
struct flock lock;
lock.l_whence = SEEK_SET;//賦值lock結(jié)構(gòu)體
lock.l_start = 0;
lock.l_len =0;
while(1)
{
lock.l_type = type;
/*根據(jù)不同的type值給文件上鎖或解鎖*/
if((fcntl(fd, F_SETLK, lock)) == 0)
{
if( lock.l_type == F_RDLCK )
printf(read lock set by %dn,getpid());
else if( lock.l_type == F_WRLCK )
printf(write lock set by %dn,getpid());
else if( lock.l_type == F_UNLCK )
printf(release lock by %dn,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 %dn,lock.l_pid);
/*該文件已有讀取鎖*/
else if( lock.l_type == F_WRLCK )
printf(write lock already set by %dn,lock.l_pid);
getchar();
}
}
}
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);
}
開兩個終端分別運行,可看到先運行的那個終端,成功上鎖,后運行的那個無效。可見寫入鎖是互斥鎖,一個時候只能有一個寫入鎖存在
select 實現(xiàn)I/O復(fù)用
I/O處理的五種模型
① 阻塞I/O模型:若所調(diào)用的I/O函數(shù)沒有完成相關(guān)的功能就會使進程掛起,直到相關(guān)數(shù)據(jù)到達才會返回。如:終端、網(wǎng)絡(luò)設(shè)備的訪問。
② 非阻塞模型:當(dāng)請求的I/O操作不能完成時,則不讓進程休眠,而且返回一個錯誤。如:open、read、write訪問。
③ I/O多路轉(zhuǎn)接模型:如果請求的I/O 操作阻塞,且他不是真正阻塞I/O,而且讓其中的一個函數(shù)等待,在這期間, I/O還能進行其他操作。如:select函數(shù)。
④ 信號驅(qū)動I/O模型:在這種模型下,通過安裝一個信號處理程序,系統(tǒng)可以自動捕獲特定信號的到來,從而啟動I/O。
⑤ 異步I/O模型:在這種模型下,當(dāng)一個描述符已準(zhǔn)備好,可以啟動I/O時,進程會通知內(nèi)核。由內(nèi)核進行后續(xù)處理,這種用法現(xiàn)在較少。
select函數(shù)
傳向select的參數(shù)告訴內(nèi)核:
(1) 我們所關(guān)心的描述符。
(2) 對于每個描述符我們所關(guān)心的條件(是否讀一個給定的描述符?是否想寫一個給定的描述符?是否關(guān)心一個描述符的異常條件?)。
(3) 希望等待多長時間(可以永遠等待,等待一個固定量時間,或完全不等待)。
從s e l e c t返回時,內(nèi)核告訴我們:
(1) 已準(zhǔn)備好的描述符的數(shù)量。
(2) 哪一個描述符已準(zhǔn)備好讀、寫或異常條件。
#i nclude /* fd_set data type */
#i nclude /* struct timeval */
#i nclude /* function prototype might be here */
int select (int numfds, fd_set *readfds,
fd_set *writefds, fd_set *exceptfds, struct timeval * timeout) ;
返回:準(zhǔn)備就緒的描述符數(shù),若超時則為0,若出錯則為- 1。
timeout值:
n NULL:永遠等待,直到捕捉到信號或文件描述符已準(zhǔn)備好為止;
n 具體值: struct timeval 類型的指針,若等待為timeout時間還沒有文件描述符準(zhǔn)備好,就立即返回;
n 0:從不等待,測試所有指定 的描述符并立即返回;
先說明最后一個參數(shù),它指定愿意等待的時間。
評論