readkeyboard方法_Linux筆記(12)| 幾種并發式IO的實現方法

1f3ccdf5a8c1c22953250d809feac503.png

今天分享的是幾種實現并發式IO的方法。什么是并發式IO呢?可以簡單理解為比如要同時讀取幾個文件的數據,但是這些文件什么時候可以讀取是不確定的,要實現當某個文件可以讀取的時候就立馬去讀取,這就是并發式。首先提出一個問題:如果我們需要讀取鍵盤和鼠標的信息,當鍵盤有按下的時候把按下的內容讀取出來并且打印到屏幕上,當鼠標有動靜的時候也把鼠標的設備文件讀取出來,該怎么實現呢?首先想到的就是在主函數里寫個while(1)挨個去讀就行了,偽代碼如下:
//偽代碼while(1){??read(keyboard);??printf("keyboard...");??read(mouse);??printf("mouse...");}
這樣的程序確實可以讀取鍵盤和鼠標的內容并且打印出來,但是必須老老實實按照代碼里的,先讀鍵盤,再讀鼠標這樣往復,如果用戶想要先讀鼠標,再讀鍵盤,抱歉,它會卡在前面這個read這里,因為read函數是阻塞式的,沒有讀到東西它就一直卡在那里。這顯然不是我們希望的,我們希望像按鍵盤就按鍵盤,想動鼠標就動鼠標,并且它都能打印出來。于是,有了以下幾種方法來解決這個問題。一、以非阻塞的方式來打開文件在使用open函數的時候,加上O_NONBLOCK屬性,變為非阻塞,而標準輸入一開始就打開了,對應文件描述符為0,所以不能用上面的方法,應該用fcntl函數來添加。變為非阻塞式的好處就是當read沒有讀到什么東西的時候會立馬返回,不會卡在那里。代碼如下:
#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);    // 先獲取原來的flag  flag |= O_NONBLOCK;        // 添加非阻塞屬性  fcntl(0, F_SETFL, flag);    // 更新flag    while(1)    {        memset(buf,0,sizeof(buf));       ret= read(fd,buf,50);          //讀鼠標    //    if(ret<0)    //    {    //        printf("read mouse ret=%d\n",ret);    //        perror("read mouse failed");    //      //  return 0;    //    }        if(ret>0)       {           printf("讀出的鼠標內容是:[%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("讀出的鍵盤內容是:[%s]\n",buf);       }    }    return 0;}
上面的代碼其實就實現了不管是按下鍵盤,還是點擊鼠標,都能及時反應,打印出數據。但是還有更好的方法,使用系統里帶的select函數或者是poll函數來監聽IO的狀況。二、使用select函數或者poll函數select函數和poll函數功能上差不多,是Unix兩個不同的派系衍生出來的函數,后來linux把它們都吸收了。select函數在上一節使用到了,可以回顧一下:Linux筆記(11)| 網絡編程之自己動手寫一個服務器和客戶端select函數首先把把要監聽的文件描述符fd添加到一個集合里面,然后調用select函數去監聽,通過返回值可以判斷監聽的fd的狀態,比如已經可寫了、或者是可讀了。代碼如下:
#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("讀鼠標:[%s]\n",buf);            }           if(FD_ISSET(0,&myset))            {                memset(buf,0,sizeof(buf));                read(0,buf,5);                printf("讀鍵盤:[%s]\n",buf);            }        }   }        return 0;}
poll函數實現的功能差不多,只是用法上有些不一樣,這里直接把代碼貼上:
#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);   //這里沒加換行就不會及時打印                }                            }    }    return 0;}
三、使用異步IO第三種方法就是使用異步IO,這種方法類似于中斷,就是在主函數里來處理鼠標(或者鍵盤也一樣),然后注冊一個異步IO事件,當有鍵盤按下的時候,產生一個異步IO信號,這個信號就會觸發一個注冊號的函數來處理它。代碼如下:
#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;    }    // 把鼠標的文件描述符設置為可以接受異步IO    flag=fcntl(fd,F_GETFL);    flag|=O_ASYNC;    fcntl(fd,F_SETFL,flag);    // 把異步IO事件的接收進程設置為當前進程    fcntl(fd,F_SETOWN,getpid());    // 注冊當前進程的SIGIO信號捕獲函數     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);}
以上是今天分享的幾種方法,實際上還可以用多進程或者多線程的方法,這在上一節里也有涉及,這里就不多說了。
猜你喜歡:Linux筆記(11)| 網絡編程之自己動手寫一個服務器和客戶端基于紅外傳輸的多點溫度采集系統教你如何用蜂鳴器演奏樂譜

def416c76b046349bfb57623bfc26618.gif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/270635.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/270635.shtml
英文地址,請注明出處:http://en.pswp.cn/news/270635.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Swift基本語法學習筆記

Swift與OC的不同點 導入框架的方式 OC使用#import <UIKit/UIKit.h>Swift使用import UIKit定義標識符的方式 Swift中定義標識符,必須指定該標識符是一個常量還是一個變量語句結束后的標志 Swift可以不用分號";"分割(只限于一行有一條語句時)OC需要分號進行分割打…

網絡知識:IP地址的概念以及IPV4和IPV6的區別

小伙伴們看到上面的機房了嗎&#xff1f;成千上萬臺服務器他們都少不了一個小小的IP地址&#xff0c;每臺服務器都配置了一個或多個IP。今天電腦學習微信公眾號小編就帶大家詳細了解下IP地址都是什么&#xff1f; IP地址&#xff08;Internet Protocol Address&#xff09;是指…

新安裝Win10操作系統有必要設置的幾個技巧

目錄 1、控制面版、回收站、網絡等圖標放到桌面 2、找回Win10系統刪除提示框 3、關閉電腦休眠并刪除hiberfil.sys 睡眠緩存文件 3、關閉Microsoft Store自動更新 4、卸載Win10自帶的軟件 5、關閉自動播放功能 6、刪除離線地圖文件并禁止更新離線地圖 新安裝Win10操作系統有必要…

apk私鑰_獲取APK證書MD5、SHA1、SHA256等秘鑰

一1.先把apk解壓2.在META_INF目錄下找到xxx.RSA文件3.確保安裝了jdk并且正確配置了環境變量4.cmd中執行keytool -printcert -file xxxx.RSA目錄image.png二1.確保安裝了jdk并且正確配置了環境變量。2.cmd中執行keytool -printcert -jarfile xxx.apk運行效果如下&#xff1a;ima…

查看某個端口的進程 lsof -i:端口號

查看某個端口的進程 lsof -i:端口號

10.27 noip模擬試題

1.鋪瓷磚&#xff08;tile.cpp/c/pas&#xff09;【問題描述】有一面很長很長的墻。 你需要在這面墻上貼上兩行瓷磚。 你的手頭有兩種不同尺寸的瓷磚&#xff0c;你希望用這兩種瓷磚各貼一行。瓷磚的長可以用分數表示&#xff0c;貼在第一行的每塊瓷磚長度為 AB &#xff0c;貼…

Windows操作系統裝機必備軟件,值得收藏

??作者主頁&#xff1a;IT技術分享社區 ??作者簡介&#xff1a;大家好,我是IT技術分享社區的博主&#xff0c;從事C#、Java開發九年&#xff0c;對數據庫、C#、Java、前端、運維、電腦技巧等經驗豐富。 ??個人榮譽&#xff1a; 數據庫領域優質創作者&#x1f3c6;&#x…

最詳細的Mac下安裝nacos教程來了

什么是 Nacos 概覽 歡迎來到 Nacos 的世界&#xff01; Nacos 致力于幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集&#xff0c;幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理。 Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平臺。…

android php mysql json 查詢_android php mysql json

$con mysql_connect("localhost", "db163810_f", "1e6969e2");if (!$con){die(不能建立連接: . mysql_error());}$db_selected mysql_select_db("db163810",$con);mysql_query("SET NAMES utf8");if (!$db_selected){die…

純css改變下拉列表select框的默認樣式

下列CSS就可以解決&#xff0c;原理是將瀏覽器默認的下拉框樣式清除&#xff0c;然后應用上自己的&#xff0c;再附一張向右對齊小箭頭的圖片即可。 select {/*Chrome和Firefox里面的邊框是不一樣的&#xff0c;所以復寫了一下*/border: solid 1px #000;/*很關鍵&#xff1a;將…

電腦軟件:推薦5款實用的效率軟件

目錄 1、圖片管理神器-Image Tuner 2、系統維護神器-Dism 3、桌面效率神器-蜂窩桌面整理 4、鍵鼠模擬軟件-按鍵精靈 5、書簽管理神器-Toby for Chrome 今天小編大家推薦5款實用的效率神器&#xff0c;希望對大家能有所幫助&#xff01; 1、圖片管理神器-Image Tuner 1000張圖片…

SpringCloud版本說明

SpringCloud包含了眾多子項目&#xff0c;每一個子項目發布時間不一定一致&#xff0c;所以采用了倫敦地鐵站為版本說明&#xff0c;而不是數字。并且從A開始是第一個發布版&#xff0c;B是第二個&#xff0c;以此類推。 SpringCloud版本SpringBoot版本Greenwich(格林威治)2.1…

JQuery中$.ajax()方法參數詳解

url: 要求為String類型的參數&#xff0c;&#xff08;默認為當前頁地址&#xff09;發送請求的地址。 type: 要求為String類型的參數&#xff0c;請求方式&#xff08;post或get&#xff09;默認為get。注意其他http請求方法&#xff0c;例如put和 delete也可以使用&#xff0…

數據庫:Redis數據庫優點介紹

1、速度快 不需要等待磁盤的IO&#xff0c;在內存之間進行的數據存儲和查詢&#xff0c;速度非常快。當然&#xff0c;緩存的數據總量不能太大&#xff0c;因為受到物理內存空間大小的限制。 2、支持多種數據庫類型 豐富的數據結構 除了string之外&#xff0c;還有list、hash、…

bat-bat-bat (重要的事情說三遍)

去年noip前prey親授&#xff0c;當時就覺得這是個好東西&#xff01;非常好&#xff01;然后我就沒學會。接著最近被安利小紅的bat&#xff01;&#xff01;&#xff01; 小紅bat&#xff01;&#xff01;&#xff01; get&#xff01;&#xff01;&#xff01;謝小紅&#xff…

mysql開方_MySQL數學函數的實際用法

此文章主要向大家描述的是MySQL數學函數的實際用法以及在實際操作中值得大家注意的問題&#xff0c;MySQL數學函數是MySQL函數中經常被用到的&#xff0c;所以對其有一定的了解還是有你有所幫助的。ABS (number2 ) //絕對值BIN (decimal_number ) //十進制轉二進制CEILING (num…

POJ 2323 貪心

題意&#xff1a; 思路&#xff1a; 貪 貪 貪 如果當前的c>之前的cs 那么之前的合適 一直貪下去就好了 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int n,s,rec1,c[105…

mysql調度觸發器,MySQL觸發器:達到某個datetime時更新

I want to create a MySQL trigger that updates a table everytime one of the datetime rows in a different table reaches a datetime lower than now.How would I accomplish this? Is that even possible?To illustrate:table_1 table_2-------- ------------------- -…

實驗二簡化版C語言中文理解程序文法

<程序>&#xff1a;&#xff1a;begin<語句串>end <語句串>&#xff1a;&#xff1a;<語句>{;<語句>} <語句>&#xff1a;&#xff1a;<賦值語句> <賦值語句>&#xff1a;&#xff1a;ID<表達式> <表達式>&#x…