readkeyboard方法_Linux笔记(12)| 几种并发式IO的实现方法
生活随笔
收集整理的這篇文章主要介紹了
readkeyboard方法_Linux笔记(12)| 几种并发式IO的实现方法
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
今天分享的是幾種實(shí)現(xiàn)并發(fā)式IO的方法。什么是并發(fā)式IO呢?可以簡(jiǎn)單理解為比如要同時(shí)讀取幾個(gè)文件的數(shù)據(jù),但是這些文件什么時(shí)候可以讀取是不確定的,要實(shí)現(xiàn)當(dāng)某個(gè)文件可以讀取的時(shí)候就立馬去讀取,這就是并發(fā)式。首先提出一個(gè)問(wèn)題:如果我們需要讀取鍵盤和鼠標(biāo)的信息,當(dāng)鍵盤有按下的時(shí)候把按下的內(nèi)容讀取出來(lái)并且打印到屏幕上,當(dāng)鼠標(biāo)有動(dòng)靜的時(shí)候也把鼠標(biāo)的設(shè)備文件讀取出來(lái),該怎么實(shí)現(xiàn)呢?首先想到的就是在主函數(shù)里寫個(gè)while(1)挨個(gè)去讀就行了,偽代碼如下://偽代碼while(1){??read(keyboard);??printf("keyboard...");??read(mouse);??printf("mouse...");}這樣的程序確實(shí)可以讀取鍵盤和鼠標(biāo)的內(nèi)容并且打印出來(lái),但是必須老老實(shí)實(shí)按照代碼里的,先讀鍵盤,再讀鼠標(biāo)這樣往復(fù),如果用戶想要先讀鼠標(biāo),再讀鍵盤,抱歉,它會(huì)卡在前面這個(gè)read這里,因?yàn)閞ead函數(shù)是阻塞式的,沒(méi)有讀到東西它就一直卡在那里。這顯然不是我們希望的,我們希望像按鍵盤就按鍵盤,想動(dòng)鼠標(biāo)就動(dòng)鼠標(biāo),并且它都能打印出來(lái)。于是,有了以下幾種方法來(lái)解決這個(gè)問(wèn)題。一、以非阻塞的方式來(lái)打開文件在使用open函數(shù)的時(shí)候,加上O_NONBLOCK屬性,變?yōu)榉亲枞?#xff0c;而標(biāo)準(zhǔn)輸入一開始就打開了,對(duì)應(yīng)文件描述符為0,所以不能用上面的方法,應(yīng)該用fcntl函數(shù)來(lái)添加。變?yōu)榉亲枞降暮锰幘褪钱?dāng)read沒(méi)有讀到什么東西的時(shí)候會(huì)立馬返回,不會(huì)卡在那里。代碼如下:#include #include #include #include #include #include #define pathname "/dev/input/mice"int main(){ int fd; int ret; char buf[100]={0}; fd=open(pathname,O_RDWR | O_NONBLOCK); if(fd<0) { perror("open failed"); return 0; } flag = fcntl(0, F_GETFL); // 先獲取原來(lái)的flag flag |= O_NONBLOCK; // 添加非阻塞屬性 fcntl(0, F_SETFL, flag); // 更新flag while(1) { memset(buf,0,sizeof(buf)); ret= read(fd,buf,50); //讀鼠標(biāo) // if(ret<0) // { // printf("read mouse ret=%d\n",ret); // perror("read mouse failed"); // // return 0; // } if(ret>0) { printf("讀出的鼠標(biāo)內(nèi)容是:[%s]\n",buf); } memset(buf,0,sizeof(buf)); ret= read(0,buf,5); //讀鍵盤 // if(ret<0) // { // perror("read keyboard failed"); // printf("read keyboard ret=%d\n",ret); // // return 0; // } if(ret>0) { printf("讀出的鍵盤內(nèi)容是:[%s]\n",buf); } } return 0;}上面的代碼其實(shí)就實(shí)現(xiàn)了不管是按下鍵盤,還是點(diǎn)擊鼠標(biāo),都能及時(shí)反應(yīng),打印出數(shù)據(jù)。但是還有更好的方法,使用系統(tǒng)里帶的select函數(shù)或者是poll函數(shù)來(lái)監(jiān)聽I(yíng)O的狀況。二、使用select函數(shù)或者poll函數(shù)select函數(shù)和poll函數(shù)功能上差不多,是Unix兩個(gè)不同的派系衍生出來(lái)的函數(shù),后來(lái)linux把它們都吸收了。select函數(shù)在上一節(jié)使用到了,可以回顧一下:Linux筆記(11)| 網(wǎng)絡(luò)編程之自己動(dòng)手寫一個(gè)服務(wù)器和客戶端select函數(shù)首先把把要監(jiān)聽的文件描述符fd添加到一個(gè)集合里面,然后調(diào)用select函數(shù)去監(jiān)聽,通過(guò)返回值可以判斷監(jiān)聽的fd的狀態(tài),比如已經(jīng)可寫了、或者是可讀了。代碼如下:#include #include #include #include #include #include #include #include #define pathname "/dev/input/mice"int main(void){ int ret; int fd; char buf[200]; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; fd_set myset; fd=open(pathname,O_RDONLY); if(fd<0) { perror("open mice failed"); return 0; } while(1) { FD_ZERO(&myset); FD_SET(0, &myset); FD_SET(fd, &myset); ret=select(fd+1,&myset,NULL,NULL,NULL); if(ret<0) { perror("select"); return 0; } else if(ret==0) { printf("time out\n"); sleep(2); } else { if( FD_ISSET(fd,&myset)) { memset(buf,0,sizeof(buf)); read(fd,buf,5); printf("讀鼠標(biāo):[%s]\n",buf); } if(FD_ISSET(0,&myset)) { memset(buf,0,sizeof(buf)); read(0,buf,5); printf("讀鍵盤:[%s]\n",buf); } } } return 0;}poll函數(shù)實(shí)現(xiàn)的功能差不多,只是用法上有些不一樣,這里直接把代碼貼上:#include #include #include #include #include #include #include #define pathname "/dev/input/mice"int main(void){ int fd; int ret; char buf[100]; struct pollfd mypoll[2]={0}; fd=open(pathname,O_RDONLY); if(fd<0) { perror("open failed"); return 0; } while(1) { mypoll[0].fd=0; mypoll[0]. events=POLLIN; mypoll[1].fd=fd; mypoll[1]. events=POLLIN; ret=poll(mypoll,fd+1,10000); if(ret<0) { perror("poll"); return 0; } else if(ret==0) { printf("time out\n"); } else { // printf("mypoll.revents=%d\n",mypoll.revents); // printf("mypoll.events=%d\n",mypoll.events); if(mypoll[0].revents==mypoll[0].events) { memset(buf,0,sizeof(buf)); ret=read(0,buf,10); if(ret<0) { perror("read keyboard failed "); return 0; } printf("read keyboard:[%s]",buf); } if(mypoll[1].revents==mypoll[1].events) { memset(buf,0,sizeof(buf)); ret=read(fd,buf,2); if(ret<0) { perror("read mouse failed "); return 0; } printf("read mouse:[%s]\n",buf); //這里沒(méi)加換行就不會(huì)及時(shí)打印 } } } return 0;}三、使用異步IO第三種方法就是使用異步IO,這種方法類似于中斷,就是在主函數(shù)里來(lái)處理鼠標(biāo)(或者鍵盤也一樣),然后注冊(cè)一個(gè)異步IO事件,當(dāng)有鍵盤按下的時(shí)候,產(chǎn)生一個(gè)異步IO信號(hào),這個(gè)信號(hào)就會(huì)觸發(fā)一個(gè)注冊(cè)號(hào)的函數(shù)來(lái)處理它。代碼如下:#include #include #include #include #include #include #include #include typedef void (*sighandler_t)(int);#define pathname "/dev/input/mice"void handler(int sig);char buf[200]; int fd;int main(void){ int flag; int ret; fd=open(pathname,O_RDONLY); if(fd<0) { perror("open failed"); return 0; } // 把鼠標(biāo)的文件描述符設(shè)置為可以接受異步IO flag=fcntl(fd,F_GETFL); flag|=O_ASYNC; fcntl(fd,F_SETFL,flag); // 把異步IO事件的接收進(jìn)程設(shè)置為當(dāng)前進(jìn)程 fcntl(fd,F_SETOWN,getpid()); // 注冊(cè)當(dāng)前進(jìn)程的SIGIO信號(hào)捕獲函數(shù) signal(SIGIO,handler); while(1) { memset(buf,0,sizeof(buf)); ret=read(0,buf,10); // if(ret<0) // { // perror("read failed"); // return 0; // } if(ret>0) printf("read keyboard :[%s]\n",buf); //sleep(2); } return 0;}void handler(int sig){ int ret; if(sig!=SIGIO) return; memset(buf,0,sizeof(buf)); ret=read(fd,buf,5); if(ret<0) { perror("read failed"); return ; } printf("read mouse :[%s]\n",buf);}以上是今天分享的幾種方法,實(shí)際上還可以用多進(jìn)程或者多線程的方法,這在上一節(jié)里也有涉及,這里就不多說(shuō)了。
猜你喜歡:Linux筆記(11)| 網(wǎng)絡(luò)編程之自己動(dòng)手寫一個(gè)服務(wù)器和客戶端基于紅外傳輸?shù)亩帱c(diǎn)溫度采集系統(tǒng)教你如何用蜂鳴器演奏樂(lè)譜
猜你喜歡:Linux筆記(11)| 網(wǎng)絡(luò)編程之自己動(dòng)手寫一個(gè)服務(wù)器和客戶端基于紅外傳輸?shù)亩帱c(diǎn)溫度采集系統(tǒng)教你如何用蜂鳴器演奏樂(lè)譜
總結(jié)
以上是生活随笔為你收集整理的readkeyboard方法_Linux笔记(12)| 几种并发式IO的实现方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: air android 通信,Andro
- 下一篇: Linux 多线程开发-等待线程结束pt