驅(qū)動(dòng)程序運(yùn)行在內(nèi)核空間中,應(yīng)用程序運(yùn)行在用戶空間中,兩者是不能直接通信的。但在實(shí)際應(yīng)用中,在設(shè)備已經(jīng)準(zhǔn)備好的時(shí)候,我們希望通知用戶程序設(shè)備已經(jīng)ok,用戶程序可以讀取了,這樣應(yīng)用程序就不需要一直查詢?cè)撛O(shè)備的狀態(tài),從而節(jié)約了資源,這就是異步通知。好,那下一個(gè)問(wèn)題就來(lái)了,這個(gè)過(guò)程如何實(shí)現(xiàn)呢?簡(jiǎn)單,兩方面的工作。
成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的鯉城網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
一 驅(qū)動(dòng)方面:
1. 在設(shè)備抽象的數(shù)據(jù)結(jié)構(gòu)中增加一個(gè)struct fasync_struct的指針
2. 實(shí)現(xiàn)設(shè)備操作中的fasync函數(shù),這個(gè)函數(shù)很簡(jiǎn)單,其主體就是調(diào)用內(nèi)核的fasync_helper函數(shù)。
3. 在需要向用戶空間通知的地方(例如中斷中)調(diào)用內(nèi)核的kill_fasync函數(shù)。
4. 在驅(qū)動(dòng)的release方法中調(diào)用前面定義的fasync函數(shù)
呵呵,簡(jiǎn)單吧,就三點(diǎn)。其中fasync_helper和kill_fasync都是內(nèi)核函數(shù),我們只需要調(diào)用就可以了。在
1中定義的指針是一個(gè)重要參數(shù),fasync_helper和kill_fasync會(huì)使用這個(gè)參數(shù)。
二 應(yīng)用層方面
1. 利用signal或者sigaction設(shè)置SIGIO信號(hào)的處理函數(shù)
2. fcntl的F_SETOWN指令設(shè)置當(dāng)前進(jìn)程為設(shè)備文件owner
3. fcntl的F_SETFL指令設(shè)置FASYNC標(biāo)志
完成了以上友凱的工作的話,當(dāng)內(nèi)核執(zhí)行到kill_fasync函數(shù),用戶空間SIGIO函數(shù)的處理函數(shù)就會(huì)被調(diào)用了。
呵呵,看起來(lái)不是很復(fù)雜把,讓我們結(jié)合具體代碼看看就更明白了。
先從應(yīng)用層代碼開(kāi)始吧:
#include sys/types.h
#include sys/stat.h搏告坦
#include stdio.h
#include fcntl.h
#include signal.h
#include unistd.h
#define MAX_LEN 100
//處理函數(shù),沒(méi)什么好講的,用戶自己定義
void input_handler(int num)
{
char data[MAX_LEN];
int len;
//讀取并輸出STDIN_FILENO上的輸入
len = read(STDIN_FILENO, data, MAX_LEN);
data[len] = 0;
printf("input available:%s\n", data);
}
void main()
{
int oflags;
//啟動(dòng)信號(hào)驅(qū)動(dòng)機(jī)制,將SIGIO信號(hào)同input_handler函數(shù)關(guān)聯(lián)起來(lái),一旦產(chǎn)生SIGIO信號(hào),就會(huì)執(zhí)行input_handler
signal(SIGIO, input_handler);
//STDIN_FILENO是打開(kāi)的設(shè)備文件描述符,F_SETOWN用來(lái)決定操作是干什么的,getpid()是個(gè)系統(tǒng)調(diào)用,
//功能是返回當(dāng)前進(jìn)程的進(jìn)程號(hào),整個(gè)函數(shù)的功能是STDIN_FILENO設(shè)置這個(gè)設(shè)備文件的擁有者為當(dāng)前進(jìn)基桐程。
fcntl(STDIN_FILENO, F_SETOWN, getpid());
//得到打開(kāi)文件描述符的狀態(tài)
oflags = fcntl(STDIN_FILENO, F_GETFL);
//設(shè)置文件描述符的狀態(tài)為oflags | FASYNC屬性,一旦文件描述符被設(shè)置成具有FASYNC屬性的狀態(tài),
//也就是將設(shè)備文件切換到異步操作模式。這時(shí)系統(tǒng)就會(huì)自動(dòng)調(diào)用驅(qū)動(dòng)程序的fasync方法。
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后進(jìn)入一個(gè)死循環(huán),程序什么都不干了,只有信號(hào)能激發(fā)input_handler的運(yùn)行
//如果程序中沒(méi)有這個(gè)死循環(huán),會(huì)立即執(zhí)行完畢
while (1);
}
再看驅(qū)動(dòng)層代碼,驅(qū)動(dòng)層其他部分代碼不變,就是增加了一個(gè)fasync方法的實(shí)現(xiàn)以及一些改動(dòng)
//首先是定義一個(gè)結(jié)構(gòu)體,其實(shí)這個(gè)結(jié)構(gòu)體存放的是一個(gè)列表,這個(gè)
//列表保存的是一系列設(shè)備文件,SIGIO信號(hào)就發(fā)送到這些設(shè)備上
static struct fasync_struct *fasync_queue;
//fasync方法的實(shí)現(xiàn)
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
//將該設(shè)備登記到fasync_queue隊(duì)列中去
retval=fasync_helper(fd,filp,on,fasync_queue);
if(retval0)
{
return retval;
}
return 0;
}
在驅(qū)動(dòng)的release方法中我們?cè)僬{(diào)用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
//..processing..
drm_fasync(-1, filp, 0);
//..processing..
}
這樣后我們?cè)谛枰牡胤剑ū热缰袛啵┱{(diào)用下面的代碼,就會(huì)向fasync_queue隊(duì)列里的設(shè)備發(fā)送SIGIO信號(hào)
,應(yīng)用程序收到信號(hào),執(zhí)行處理程序
if (fasync_queue)
kill_fasync(fasync_queue, SIGIO, POLL_IN);
好了,這下大家知道該怎么用異步通知機(jī)制了吧?
以下是幾點(diǎn)說(shuō)明[1]:
1 兩個(gè)函數(shù)的原型
int fasync_helper(struct inode *inode, struct file *filp, int mode, struct fasync_struct **fa);
一個(gè)"幫忙者", 來(lái)實(shí)現(xiàn) fasync 設(shè)備方法. mode 參數(shù)是傳遞給方法的相同的值, 而 fa 指針指向一個(gè)設(shè)
備特定的 fasync_struct *
void kill_fasync(struct fasync_struct *fa, int sig, int band);
如果這個(gè)驅(qū)動(dòng)支持異步通知, 這個(gè)函數(shù)可用來(lái)發(fā)送一個(gè)信號(hào)到登記在 fa 中的進(jìn)程.
2.
fasync_helper 用來(lái)向等待異步信號(hào)的設(shè)備鏈表中添加或者刪除設(shè)備文件, kill_fasync被用來(lái)通知擁有相關(guān)設(shè)備的進(jìn)程. 它的參數(shù)是被傳遞的信號(hào)(常常是 SIGIO)和 band, 這幾乎都是 POLL_IN[25](但是這可用來(lái)發(fā)送"緊急"或者帶外數(shù)據(jù), 在網(wǎng)絡(luò)代碼里).
一 驅(qū)動(dòng)方面:
1. 在設(shè)備抽象的數(shù)據(jù)結(jié)構(gòu)中增加一個(gè)struct fasync_struct的指針
2. 實(shí)現(xiàn)設(shè)備操作中的fasync函數(shù),這個(gè)函數(shù)很簡(jiǎn)單,其主體就是調(diào)用內(nèi)嘩型核的fasync_helper函數(shù)。
3. 在需要向用戶空間通知的地方(例如中斷中)調(diào)用內(nèi)核的kill_fasync函數(shù)。
4. 在驅(qū)動(dòng)的release方法中調(diào)用前面定義的fasync函數(shù)
呵呵,簡(jiǎn)單吧,就三點(diǎn)。其中fasync_helper和kill_fasync都是內(nèi)核函數(shù),我們只需要調(diào)用就可以了。在1中定義的指針是一個(gè)重要參數(shù),fasync_helper和kill_fasync會(huì)使用這個(gè)參數(shù)。
二 應(yīng)用層方面
1. 利用signal或者sigaction設(shè)置SIGIO信號(hào)的處理函數(shù)
2. fcntl的F_SETOWN指令設(shè)置當(dāng)前進(jìn)程為設(shè)備文件owner
3. fcntl的F_SETFL指令設(shè)置FASYNC標(biāo)志
完成了以上的工作的話,當(dāng)內(nèi)核執(zhí)行到kill_fasync函數(shù),用戶空間SIGIO函數(shù)的處理函數(shù)就會(huì)被調(diào)用了。
呵呵,看起來(lái)不是很復(fù)雜把,讓我們結(jié)合具體代碼看看就更明白了。
先從應(yīng)用層代碼開(kāi)始吧:
#include sys/types.h
#include sys/stat.h
#include stdio.h
#include fcntl.h
#include signal.h
#include unistd.h
#define MAX_LEN 100
//處理函數(shù),沒(méi)什么好講的,用戶自己定義
void input_handler(int num)
{
char data[MAX_LEN];
int len;
//讀取并輸出STDIN_FILENO上的輸入
len = read(STDIN_FILENO, data, MAX_LEN);
data[len] = 0;
printf("input available:%s\n", data);
}
void main()
{
int oflags;
//啟動(dòng)信號(hào)驅(qū)動(dòng)機(jī)制,將SIGIO信號(hào)同input_handler函數(shù)關(guān)聯(lián)起來(lái),一旦產(chǎn)生SIGIO信號(hào),就會(huì)執(zhí)行input_handler
signal(SIGIO, input_handler);
//STDIN_FILENO是打開(kāi)的設(shè)備文件描述符,F_SETOWN用來(lái)決定操作是干什么的,getpid()是個(gè)系統(tǒng)調(diào)用,
//功能是返回當(dāng)前進(jìn)程的進(jìn)程號(hào),整個(gè)函數(shù)的功能是STDIN_FILENO設(shè)置這個(gè)設(shè)備文件的擁有者為當(dāng)前進(jìn)程。
fcntl(STDIN_FILENO, F_SETOWN, getpid());
//得到打開(kāi)文件描述符的狀態(tài)
oflags = fcntl(STDIN_FILENO, F_GETFL);
//設(shè)茄蘆粗置文件描述符的狀態(tài)為oflags | FASYNC屬性,一旦文件描述符被設(shè)置成具有FASYNC屬性的狀態(tài),
//也就是將設(shè)備文件切換到異步操作模式。這時(shí)系統(tǒng)就會(huì)自動(dòng)調(diào)用驅(qū)動(dòng)程序的fasync方法。
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后進(jìn)顫鎮(zhèn)入一個(gè)死循環(huán),程序什么都不干了,只有信號(hào)能激發(fā)input_handler的運(yùn)行
//如果程序中沒(méi)有這個(gè)死循環(huán),會(huì)立即執(zhí)行完畢
while (1);
}
再看驅(qū)動(dòng)層代碼,驅(qū)動(dòng)層其他部分代碼不變,就是增加了一個(gè)fasync方法的實(shí)現(xiàn)以及一些改動(dòng)
//首先是定義一個(gè)結(jié)構(gòu)體,其實(shí)這個(gè)結(jié)構(gòu)體存放的是一個(gè)列表,這個(gè)
//列表保存的是一系列設(shè)備文件,SIGIO信號(hào)就發(fā)送到這些設(shè)備上
static struct fasync_struct *fasync_queue;
//fasync方法的實(shí)現(xiàn)
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
//將該設(shè)備登記到fasync_queue隊(duì)列中去
retval=fasync_helper(fd,filp,on,fasync_queue);
if(retval0)
{
return retval;
}
return 0;
}
在驅(qū)動(dòng)的release方法中我們?cè)僬{(diào)用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
//..processing..
drm_fasync(-1, filp, 0);
//..processing..
}這樣后我們?cè)谛枰牡胤剑ū热缰袛啵┱{(diào)用下面的代碼,就會(huì)向fasync_queue隊(duì)列里的設(shè)備發(fā)送SIGIO信號(hào)
,應(yīng)用程序收到信號(hào),執(zhí)行處理程序
if (fasync_queue)
kill_fasync(fasync_queue, SIGIO, POLL_IN);
可以調(diào)用shell 中命游行令測(cè)碰磨喚笑凱試
sleep?600??//單位秒
Linux中最常用的IO模型是同步IO,在這個(gè)模型中,當(dāng)請(qǐng)求發(fā)出之后,應(yīng)用程序就會(huì)阻塞,直到請(qǐng)求滿足條件為止。這是一種很好的解決方案,調(diào)用應(yīng)用程序在等待IO完成的時(shí)候不需要占用CPU,但是在很多場(chǎng)景中,IO請(qǐng)求可能需要和CPU消耗交疊,以充分利用CPU和IO提高吞吐率。
下圖描繪了異步IO的時(shí)序,應(yīng)用程序發(fā)起IO操作后,直接開(kāi)始執(zhí)行,并不等待IO結(jié)束,它要么過(guò)一段時(shí)間來(lái)查詢之前的IO請(qǐng)求完成情況,要么IO請(qǐng)求差襲正完成了會(huì)自動(dòng)被調(diào)用與IO完成綁定的回調(diào)函數(shù)。
Linux的AIO有多種實(shí)現(xiàn),其中一種實(shí)現(xiàn)是在用戶空間的glibc庫(kù)中實(shí)現(xiàn)的,本質(zhì)上是借用了多線程模型,用開(kāi)啟的新的線程以同步的方式做IO,新的AIO輔助線程與發(fā)起AIO的線程以pthread_cond_signal()的形式進(jìn)行線程間的同步,glibc的AIO主要包含以下函數(shù):
1、aio_read()
aio_read()函數(shù)請(qǐng)求對(duì)一個(gè)有效的文件描述符進(jìn)行異步讀操作。這個(gè)文件描述符可以代表一個(gè)文件、套接字,甚至管道,aio_read()函禪迅數(shù)原型如下:
aio_read()函數(shù)在請(qǐng)求進(jìn)行排隊(duì)之后就會(huì)立即返回(盡管讀操作并未完成),如果執(zhí)行成功就返回0,如果出現(xiàn)錯(cuò)誤就返回-1。參數(shù)aiocb(AIO I/O Control Block)結(jié)構(gòu)體包含了傳輸?shù)乃行畔?,以及為AIO操作準(zhǔn)備的用戶虛悔空間緩沖區(qū)。在產(chǎn)生IO完成通知時(shí),aiocb結(jié)構(gòu)就被用來(lái)唯一標(biāo)識(shí)所完成的IO操作。
2.aio_write()
aio_write()函數(shù)用來(lái)請(qǐng)求一個(gè)異步寫操作。函數(shù)原型如下:
aio_write()函數(shù)會(huì)立即返回,并且它的請(qǐng)求以及被排隊(duì)(成功時(shí)返回值為0,失敗時(shí)返回值為-1)
3.aio_error()
aio_error()函數(shù)被用來(lái)確定請(qǐng)求的狀態(tài),其原型如下:
該函數(shù)的返回:
4.aio_return()
異步IO和同步阻塞IO方式之間有一個(gè)區(qū)別就是不能立即訪問(wèn)函數(shù)的返回狀態(tài),因?yàn)楫惒絀O沒(méi)有阻塞在read()調(diào)用上。在標(biāo)準(zhǔn)的同步阻塞read()調(diào)用中,返回狀態(tài)是在該函數(shù)返回時(shí)提供的。
但是在異步IO中,我們要用aio_return()函數(shù),原型如下:
只有在aio_error()調(diào)用確定請(qǐng)求已經(jīng)完成(可能成功、也可能發(fā)生了錯(cuò)誤)之后,才會(huì)調(diào)用這個(gè)函數(shù),aio_return()的返回值就等價(jià)于同步情況中read()或者write系統(tǒng)調(diào)用的返回值。
5.aio_suspend()
用戶可以用該函數(shù)阻塞調(diào)用進(jìn)程,直到異步請(qǐng)求完成為止,調(diào)用者提供了一個(gè)aiocb引用列表,其中任何一個(gè)完成都會(huì)導(dǎo)致aio_suspend()返回。函數(shù)原型如下:
6.aio_cancel()
該函數(shù)允許用戶取消對(duì)某個(gè)文件描述符執(zhí)行的一個(gè)或所以IO請(qǐng)求。
要取消一個(gè)請(qǐng)求,用戶需要提供文件描述符和aiocb指針,如果這個(gè)請(qǐng)求被成功取消了,那么這個(gè)函數(shù)就會(huì)返回AIO_CANCELED。如果請(qǐng)求完成了,就會(huì)返回AIO_NOTCANCELED。
7.lio_listio()
lio_listio()函數(shù)可用于同時(shí)發(fā)起多個(gè)傳輸。這個(gè)函數(shù)非常重要,它使得用戶可以在一個(gè)系統(tǒng)調(diào)用中啟動(dòng)大量的IO操作,原型如下:
mode參數(shù)可以是LIO_WAIT或者是LIO_NOWAIT。LIO_WAIT會(huì)阻塞這個(gè)調(diào)用,直到所有的IO都返回為止,若是LIO_NOWAIT模型,在IO操作完成排隊(duì)之后,該函數(shù)就會(huì)返回。list是一個(gè)aiocb的列表,最大元素的個(gè)數(shù)是由nent定義的。如果list的元素為null,lio_listio()會(huì)將其忽略。
本文題目:linux異步執(zhí)行命令 linux 異步讀寫文件
文章源于:http://jinyejixie.com/article8/ddpijop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計(jì)、做網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站維護(hù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
移動(dòng)網(wǎng)站建設(shè)知識(shí)