有意思的select~
前言
最近在寫(xiě)一個(gè)小程序,也就是簡(jiǎn)單的系統(tǒng)調(diào)用,但是神奇的是,我用的這個(gè)系統(tǒng)調(diào)用剛好就阻塞了。如果你也寫(xiě)過(guò)應(yīng)用程序,肯定也會(huì)遇到過(guò)這樣的問(wèn)題。
后來(lái),發(fā)現(xiàn)了select這個(gè)好東西,可以用來(lái)監(jiān)聽(tīng)文件描述。
select的作用
如果我們?cè)趓ead一個(gè)文件,如果文件馬上有東西返回,那是非常愉快的事情,但是經(jīng)常遇到一些情況,read不能馬上返回?cái)?shù)據(jù),這時(shí)候,會(huì)造成我們的線程阻塞,就卡在那里不動(dòng)。如果是ui界面,那情況就顯得很尷尬,你的ui卡主了,作為一個(gè)計(jì)算機(jī)用戶,那是一件非常崩潰的事情的。
人們?yōu)榱私鉀Q這個(gè)問(wèn)題,select就出現(xiàn)了。
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2)) without blocking.
select 和 pselect 允許程序監(jiān)聽(tīng)文件描述符,文件描述符是打開(kāi)文件的時(shí)候返回從一個(gè)整數(shù),這個(gè)整數(shù)代表了一個(gè)文件,大家都叫他做文件描述符。直到文件描述符準(zhǔn)備好了IO操作。
原來(lái)的代碼
#include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <linux/ioctl.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h>#define RETRY_TIMES (20) #define COM_STR "ezsp ver"int main(int argc, char * const argv[]) {int fd_in,fd_out,size;int retry_times=0;int ret=0;//char s[ ]="info\n",buffer[1024];char s[ ]="version\n",buffer[1024];printf("=== weiqifa ===Zigbee test start ...\n");printf("argc:%d\n",argc);printf("argv[0]:%s\n",argv[0]);/*打開(kāi)寫(xiě)管道文件*/fd_in=open("/dev/gateway_in",O_RDWR);if(fd_in<0){printf("===weiqifa=== open error:%d\n",fd_in);return(0);}/*打開(kāi)讀管道文件*/fd_out=open("/dev/gateway_out",O_RDWR);if(fd_out<0){printf("===weiqifa=== open error:%d\n",fd_out);return(0);}/*循環(huán)讀寫(xiě)*/do{ret = write(fd_in,s,sizeof(s));size= read(fd_out,buffer,sizeof(buffer));printf("%s",buffer);if(strncmp(COM_STR,buffer,strlen(COM_STR) -1) == 0){break;}usleep(3000);}while(retry_times++ <=RETRY_TIMES);if(retry_times>= RETRY_TIMES){printf("\nfail\n");return (-1);}/*關(guān)閉管道*/close(fd_out);close(fd_in);printf("\nsuccess\n");return (0); }修改后的代碼
#include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <linux/ioctl.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h>#define RETRY_TIMES (20) #define COM_STR "ezsp ver"int main(int argc, char * const argv[]) {int fd_in,fd_out,size;int retry_times=0;int ret=0;struct timeval tv;fd_set rdfds;/*清空rdfds*/FD_ZERO(&rdfds);//char s[ ]="info\n",buffer[1024];char s[ ]="version\n",buffer[1024];printf("=== weiqifa ===Zigbee test start ...\n");printf("argc:%d\n",argc);printf("argv[0]:%s\n",argv[0]);/*打開(kāi)寫(xiě)管道文件*/fd_in=open("/dev/gateway_in",O_RDWR);if(fd_in<0){printf("===weiqifa=== open error:%d\n",fd_in);return(0);}/*打開(kāi)讀管道文件*/fd_out=open("/dev/gateway_out",O_RDWR);if(fd_out<0){printf("===weiqifa=== open error:%d\n",fd_out);return(0);}/*循環(huán)讀寫(xiě)*/do{ret = write(fd_in,s,sizeof(s));tv.tv_sec = 1; /*秒*/tv.tv_usec = 500; /*微秒*//*添加監(jiān)聽(tīng)的設(shè)備描述符*/FD_ZERO(&rdfds);FD_SET(fd_out,&rdfds);/*監(jiān)聽(tīng)fd_out*/ret = select(fd_out+1,&rdfds,NULL,NULL,&tv);if(ret<0){printf("selcet error\r\n");retry_times = RETRY_TIMES;break;}else if(ret == 0){ /*超時(shí)*/printf("timeout \r\n");retry_times = RETRY_TIMES;break;}else{printf("ret = %d \r\n",ret);}size= read(fd_out,buffer,sizeof(buffer));printf("%s",buffer);if(strncmp(COM_STR,buffer,strlen(COM_STR) -1) == 0){break;}usleep(3000);}while(retry_times++ <=RETRY_TIMES);if(retry_times>= RETRY_TIMES){printf("\nfail\n");return (-1);}/*關(guān)閉管道*/close(fd_out);close(fd_in);printf("\nsuccess\n");return (0); }select代碼的小例子
#include <stdio.h>#include <stdlib.h>#include <sys/select.h>intmain(void){fd_set rfds;struct timeval tv;int retval;/* Watch stdin (fd 0) to see when it has input. */FD_ZERO(&rfds);FD_SET(0, &rfds);/* Wait up to five seconds. */tv.tv_sec = 5;tv.tv_usec = 0;retval = select(1, &rfds, NULL, NULL, &tv);/* Don't rely on the value of tv now! */if (retval == -1)perror("select()");else if (retval)printf("Data is available now.\n");/* FD_ISSET(0, &rfds) will be true. */elseprintf("No data within five seconds.\n");exit(EXIT_SUCCESS);}執(zhí)行 第一次執(zhí)行的時(shí)候,我沒(méi)有輸入任何內(nèi)容,這時(shí)候,select就一直監(jiān)聽(tīng)標(biāo)準(zhǔn)輸入,因?yàn)闆](méi)有輸入就一直等,等到了超時(shí)時(shí)間,程序就退出了。
第二次執(zhí)行的時(shí)候,我給標(biāo)準(zhǔn)輸入輸入東西了,select馬上就返回,并打印了數(shù)據(jù)是有效的。
深入理解select模型
理解select模型的關(guān)鍵在于理解fd_set,為說(shuō)明方便,取fd_set長(zhǎng)度為1字節(jié),fd_set中的每一bit可以對(duì)應(yīng)一個(gè)文件描述符fd。則1字節(jié)長(zhǎng)的fd_set最大可以對(duì)應(yīng)8個(gè)fd。
執(zhí)行fd_set set; FD_ZERO(&set); 則set用位表示是0000,0000。
若fd=5,執(zhí)行FD_SET(fd,&set);后set變?yōu)?001,0000(第5位置為1)
若再加入fd=2,fd=1,則set變?yōu)?001,0011
執(zhí)行select(6,&set,0,0,0)阻塞等待
若fd=1,fd=2上都發(fā)生可讀事件,則select返回,此時(shí)set變?yōu)?000,0011。注意:沒(méi)有事件發(fā)生的fd=5被清空。
最后舉個(gè)例子
執(zhí)行截圖
===========
??
PS:想加入技術(shù)群的同學(xué),加了我好友后,就給我發(fā)「籃球的大肚子」這句話,有可能機(jī)器人打瞌睡,可以多發(fā)幾次,不要發(fā)與技術(shù)無(wú)關(guān)的消息或者推廣。
如果想獲取學(xué)習(xí)資料,就在公眾號(hào)后臺(tái)回復(fù)「1024」,足夠多的學(xué)習(xí)資料可以讓你學(xué)習(xí)。
總結(jié)
以上是生活随笔為你收集整理的有意思的select~的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: php常用函数最全总结
- 下一篇: 电脑连不上wifi的三种处理办法。