pselect 和 select
pselect函数是由POSIX发明的,如今许多Unix变种都支持它。
#include <sys/select.h> #include <signal.h> #include <time.h>int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);返回:就绪描述字的个数,0-超时,-1-出错
pselect相对于通常的select有两个变化:
1、pselect使用timespec结构,而不使用timeval结构。timespec结构是POSIX的又一个发明。
struct timespec{
time_t tv_sec; //seconds
long tv_nsec; //nanoseconds
};
这两个结构的区别在于第二个成员:新结构的该成员tv_nsec指定纳秒数,而旧结构的该成员tv_usec指定微秒数。
2、pselect函数增加了第六个参数:一个指向信号掩码的指针。该参数允许程序先禁止递交某些信号,再测试由这些当前被禁止的信号处理函数设置的全局变量,然后调用pselect,告诉它重新设置信号掩码。
关于第二点,考虑下面的例子,这个程序的SIGINT信号处理函数仅仅设置全局变量intr_flag并返回。如果我们的进程阻塞于select调用,那么从信号处理函数的返回将导致select返回EINTR错误。然而调用select时,代码看起来大体如下:
if( intr_flag )handle_intr();if( (nready = select(...)) < 0 ) {if( errno == EINTR ){if( intr_flag )handle_intr();}... }
问题是在测试intr_flag和调用select之间如果有信号发生,那么要是select永远阻塞,该信号就会丢失。有了pselect后,我们可以如下可靠地编写这个例子的代码:
sigset_t newmask, oldmask, zeromask;sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGINT);sigprocmask(SIG_BLOCK, &newmask, &oldmask); //block SIGINT if(intr_flag)handle_intr();if( (nready = pselect(...,&zeromask)) < 0 ) {if(errno == EINTR){if(intr_flag)handle_intr();}... }
在测试intr_flag变量之前,我们阻塞SIGINT。当pselect被调用时,它先以空集(zeromask)取代进程的信号掩码,再检查描述字,并可能进入睡眠。然而当pselect函数返回时,进程的信号掩码又被重置为调用pselect之前的值(即SIGINT被阻塞),也就是说只有在pslecet中,SIGINT是不被阻塞的。
注意: pselect(...,&zeromask) 与 pselect(...,NULl) 意义完全不同,前者是在调用期间不阻塞任何新信号,后者和调用select相同,保持原来的信号mask。
pselect和select 这两个函数基本上是一致,但是有三个区别:
第一点 select函数用的timeout参数,是一个timeval的结构体(包含秒和微秒),然而pselect用的是一个timespec结构体(包含秒和纳秒)
第二点 select函数可能会为了指示还剩多长时间而更新timeout参数,然而pselect不会改变timeout参数
第三点 select函数没有sigmask参数,当pselect的sigmask参数为null时,两者行为时一致的。有sigmask的时候,pselect相当于如下的select()函数,在进入select()函数之前手动将信号的掩码改变,并保存之前的掩码值;select()函数执行之后,再恢复为之前的信号掩码值。
sigset_t origmask; sigprocmask(SIG_SETMASK, &sigmask, &origmask); select(nfds, &readfds, &writefds, &exceptfds, timeout); sigprocmask(SIG_SETMASK, &origmask, NULL);
例如
1:sigset_t new, old, zero;2:3:sigemptyset(&zero);4:sigemptyset(&new);5:sigaddset(&new, SIGINT);6:sigprocmask(SIG_BLOCK, &new, old);//block SIGINT7:if (intr_flag)8: handle_intr();//handle the signal9:if ((nready = pselet(..., &zero)) < 0){ 10: if (errno = EINTR){ 11: if (intr_flag) 12: handle_intr(); 13: } 14: ... 15:}
如果没有sigprocmask(SIG_BLOCK, &new, old)这行代码阻塞信号,程序执行完7,8行之后,你投递INT,于是INT立即被处理,然后进入9行阻塞。
你本意是发送INT进入handle_intr()处理信号,然后pselect全然不知情的阻塞了。
如果有sigprocmask(SIG_BLOCK, &new, old)这行代码,那么你要么在sigprocmask之前投递了INT,那么INT立即被处理,那么7,8行就可以被正确的处理。要么你在sigprocmask之后投递的INT,那么INT不会被处理,一直到pselect取消了阻塞,INT被处理。这个过程保证了你在处理一个信号结果的同时不会再有该信号被处理。
下面举几个例子来说明select和pselect以及sigprocmask的使用
1 用pselect 屏蔽信号
1 #include <time.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 #include <unistd.h> 6 #include <sys/select.h> 7 #define BUFFSIZE 80 8 void sig_int(int signo); 9 void err_sys(const char *p_error); 10 void sig_alrm(int signo) 11 { 12 char s[] ="receive"; 13 psignal(signo, s); 14 return; 15 } 16 int 17 main(int argc, char **argv) 18 { 19 int maxfdp1; 20 fd_set rset; 21 sigset_t sigmask; 22 ssize_t nread; 23 char buf[BUFFSIZE]; 24 sigset_t sigset; 25 struct sigaction act; 26 //set SIGALRM signal handler 27 act.sa_handler= sig_alrm; 28 if(sigemptyset(&act.sa_mask) ==-1) 29 err_sys("sigemptyset"); 30 act.sa_flags= 0; 31 if(sigaction(SIGALRM, &act, NULL) == -1) 32 err_sys("sigaction"); 33 //initialize signal set and addition SIGALRM into sigset 34 if(sigemptyset(&sigset) == -1) 35 err_sys("sigemptyet"); 36 if(sigaddset(&sigset, SIGALRM) == -1) 37 err_sys("sigaddset"); 38 alarm(1); 39 FD_ZERO(&rset); 40 FD_SET(STDIN_FILENO, &rset); 41 maxfdp1 = STDIN_FILENO + 1; 42 if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= 0) 43 //if (select(maxfdp1, &rset, NULL, NULL, NULL) <= 0) 44 err_sys("pselect error"); 45 if (FD_ISSET(STDIN_FILENO, &rset)) 46 { 47 if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -1) 48 err_sys("read error"); 49 if (write(STDOUT_FILENO, buf, nread) != nread) 50 err_sys("write error"); 51 } 52 exit(0); 53 } 54 void 55 sig_int(int signo) 56 { 57 char s[] ="received"; 58 psignal(signo, s); 59 return; 60 } 61 void 62 err_sys(const char *p_error) 63 { 64 perror(p_error); 65 exit(1); 66 }
上段代码如果没有CTRL+C送上一个SIGINT信号,将永远阻塞在与用户的交互上,ALARM产生的SIGALRM信号永远打断不了PSELECT,ALARM信号被成功屏蔽
2 用sigprocmask 屏蔽信号。
1 #include <time.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 #include <unistd.h> 6 #include <sys/select.h> 7 #define BUFFSIZE 80 8 void sig_int(int signo); 9 void err_sys(const char *p_error); 10 void sig_alrm(int signo) 11 { 12 char s[] ="receive"; 13 psignal(signo, s); 14 return; 15 } 16 int 17 main(int argc, char **argv) 18 { 19 int maxfdp1; 20 fd_set rset; 21 sigset_t zeromask; 22 ssize_t nread; 23 char buf[BUFFSIZE]; 24 sigset_t sigset; 25 struct sigaction act; 26 //set SIGALRM signal handler 27 act.sa_handler= sig_alrm; 28 if(sigemptyset(&act.sa_mask) ==-1) 29 err_sys("sigemptyset"); 30 if(sigemptyset(&zeromask) ==-1) 31 err_sys("sigemptyset"); 32 act.sa_flags= 0; 33 if(sigaction(SIGALRM, &act, NULL) == -1) 34 err_sys("sigaction"); 35 //initialize signal set and addition SIGALRM into sigset 36 if(sigemptyset(&sigset) == -1) 37 err_sys("sigemptyet"); 38 if(sigaddset(&sigset, SIGALRM) == -1) 39 err_sys("sigaddset"); 40 //block SIGALRMsignal 41 if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) 42 err_sys("sigprocmask"); 43 //generate SIGALRM signal 44 alarm(1); 45 FD_ZERO(&rset); 46 FD_SET(STDIN_FILENO, &rset); 47 maxfdp1 = STDIN_FILENO + 1; 48 if (select(maxfdp1, &rset, NULL, NULL, NULL)<= 0) 49 //if (pselect(maxfdp1, &rset, NULL, NULL, NULL, &zeromask)<= 0) 50 err_sys("pselect error"); 51 if (FD_ISSET(STDIN_FILENO, &rset)) 52 { 53 if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -1) 54 err_sys("read error"); 55 if (write(STDOUT_FILENO, buf, nread) != nread) 56 err_sys("write error"); 57 } 58 exit(0); 59 } 60 void 61 sig_int(int signo) 62 { 63 char s[] ="received"; 64 psignal(signo, s); 65 return; 66 } 67 void 68 err_sys(const char *p_error) 69 { 70 perror(p_error); 71 exit(1); 72 }
上段代码如果没有CTRL+C送上一个SIGINT信号,将永远阻塞在与用户的交互上,ALARM产生的SIGALRM信号永远打断不了PSELECT,ALARM信号被成功屏蔽
3 如果 上述code代码改成下面则无法屏蔽信号,因为我们使用zeromask,它不屏蔽任何信号
1 #include <time.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 #include <unistd.h> 6 #include <sys/select.h> 7 #define BUFFSIZE 80 8 void sig_int(int signo); 9 void err_sys(const char *p_error); 10 void sig_alrm(int signo) 11 { 12 char s[] ="receive"; 13 psignal(signo, s); 14 return; 15 } 16 int 17 main(int argc, char **argv) 18 { 19 int maxfdp1; 20 fd_set rset; 21 sigset_t zeromask; 22 ssize_t nread; 23 char buf[BUFFSIZE]; 24 sigset_t sigset; 25 struct sigaction act; 26 //set SIGALRM signal handler 27 act.sa_handler= sig_alrm; 28 if(sigemptyset(&act.sa_mask) ==-1) 29 err_sys("sigemptyset"); 30 if(sigemptyset(&zeromask) ==-1) 31 err_sys("sigemptyset"); 32 act.sa_flags= 0; 33 if(sigaction(SIGALRM, &act, NULL) == -1) 34 err_sys("sigaction"); 35 //initialize signal set and addition SIGALRM into sigset 36 if(sigemptyset(&sigset) == -1) 37 err_sys("sigemptyet"); 38 if(sigaddset(&sigset, SIGALRM) == -1) 39 err_sys("sigaddset"); 40 //block SIGALRMsignal 41 if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) 42 err_sys("sigprocmask"); 43 //generate SIGALRM signal 44 alarm(1); 45 FD_ZERO(&rset); 46 FD_SET(STDIN_FILENO, &rset); 47 maxfdp1 = STDIN_FILENO + 1; 48 //if (select(maxfdp1, &rset, NULL, NULL, NULL)<= 0) 49 if (pselect(maxfdp1, &rset, NULL, NULL, NULL, &zeromask)<= 0) 50 err_sys("pselect error"); 51 if (FD_ISSET(STDIN_FILENO, &rset)) 52 { 53 if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -1) 54 err_sys("read error"); 55 if (write(STDOUT_FILENO, buf, nread) != nread) 56 err_sys("write error"); 57 } 58 exit(0); 59 } 60 void 61 sig_int(int signo) 62 { 63 char s[] ="received"; 64 psignal(signo, s); 65 return; 66 } 67 void 68 err_sys(const char *p_error) 69 { 70 perror(p_error); 71 exit(1); 72 }
4 仅仅使用select,不使用sigprocmask也无法屏蔽信号。
#include <time.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <sys/select.h>#define BUFFSIZE 80void sig_int(int signo);void err_sys(const char *p_error);void sig_alrm(int signo){char s[] ="receive";psignal(signo, s);return;}intmain(int argc, char **argv){int maxfdp1;fd_set rset;sigset_t sigmask;ssize_t nread;char buf[BUFFSIZE];sigset_t sigset;struct sigaction act;//set SIGALRM signal handleract.sa_handler= sig_alrm;if(sigemptyset(&act.sa_mask) ==-1) err_sys("sigemptyset");act.sa_flags= 0;if(sigaction(SIGALRM, &act, NULL) == -1)err_sys("sigaction");//initialize signal set and addition SIGALRM into sigsetif(sigemptyset(&sigset) == -1)err_sys("sigemptyet");if(sigaddset(&sigset, SIGALRM) == -1)err_sys("sigaddset");alarm(1); FD_ZERO(&rset);FD_SET(STDIN_FILENO, &rset);maxfdp1 = STDIN_FILENO + 1;//if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= 0)if (select(maxfdp1, &rset, NULL, NULL, NULL) <= 0)err_sys("pselect error");if (FD_ISSET(STDIN_FILENO, &rset)){if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -1)err_sys("read error");if (write(STDOUT_FILENO, buf, nread) != nread)err_sys("write error");}exit(0);}voidsig_int(int signo){char s[] ="received";psignal(signo, s);return;}voiderr_sys(const char *p_error){perror(p_error);exit(1);}
5 用pselect,但信号屏蔽参数为NULL, 同使用select一样,无法屏蔽信号
1 #include <time.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 #include <unistd.h> 6 #include <sys/select.h> 7 #define BUFFSIZE 80 8 void sig_int(int signo); 9 void err_sys(const char *p_error); 10 void sig_alrm(int signo) 11 { 12 char s[] ="receive"; 13 psignal(signo, s); 14 return; 15 } 16 int 17 main(int argc, char **argv) 18 { 19 int maxfdp1; 20 fd_set rset; 21 sigset_t sigmask; 22 ssize_t nread; 23 char buf[BUFFSIZE]; 24 sigset_t sigset; 25 struct sigaction act; 26 //set SIGALRM signal handler 27 act.sa_handler= sig_alrm; 28 if(sigemptyset(&act.sa_mask) ==-1) 29 err_sys("sigemptyset"); 30 act.sa_flags= 0; 31 if(sigaction(SIGALRM, &act, NULL) == -1) 32 err_sys("sigaction"); 33 //initialize signal set and addition SIGALRM into sigset 34 if(sigemptyset(&sigset) == -1) 35 err_sys("sigemptyet"); 36 if(sigaddset(&sigset, SIGALRM) == -1) 37 err_sys("sigaddset"); 38 alarm(1); 39 FD_ZERO(&rset); 40 FD_SET(STDIN_FILENO, &rset); 41 maxfdp1 = STDIN_FILENO + 1; 42 //if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= 0) 43 if (pselect(maxfdp1, &rset, NULL, NULL, NULL,NULL) <= 0) 44 //if (select(maxfdp1, &rset, NULL, NULL, NULL) <= 0) 45 err_sys("pselect error"); 46 if (FD_ISSET(STDIN_FILENO, &rset)) 47 { 48 if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -1) 49 err_sys("read error"); 50 if (write(STDOUT_FILENO, buf, nread) != nread) 51 err_sys("write error"); 52 } 53 exit(0); 54 } 55 void 56 sig_int(int signo) 57 { 58 char s[] ="received"; 59 psignal(signo, s); 60 return; 61 } 62 void 63 err_sys(const char *p_error) 64 { 65 perror(p_error); 66 exit(1); 67 }
pselect 和 select相关推荐
- select与pselect的信号屏蔽
pselect() 函数的原型是:int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set ...
- I/O 多路复用之select
转载:http://blog.csdn.net/u012432778/article/details/47347133 概述 Linux提供了三种 I/O 多路复用方案:select,poll和epo ...
- usleep头文件_Linunx的sleep,usleep,select,nonasleep对比与应用
前言 时钟换算: 1秒(s) = 1000 毫秒(ms) = 1,000,000 微秒(μs) = 1,000,000,000 纳秒(ns) = 1,000,000,000,000 皮秒(ps) 程序 ...
- sqlite-1.0.0源码执行的基本流程概述
sqlite-1.0.0原理概述 sqlite是一款嵌入式的轻量级的数据库,首个版本诞生于2000年,该数据库遵守ACID的关系数据库管理系统,SQLite不是一个cs架构的数据库引擎,而是被集成在用 ...
- 问题集锦(16-20)
Problem 16. What's the difference between soft link and hard link file? Ans: Hard link file is nothi ...
- [单刷 APUE 系列] 第十四章——高级 I/O
非阻塞I/O 在最前面,我们讲过IO分成带缓冲的IO和不带缓冲的IO,但是实际上,这个区别并不是很大,因为缓冲区并没有影响到实际的读写.我们知道,系统调用实际上分成两种,高速的系统调用和低速的系统调用 ...
- c++ IO多路复用
1. 什么是IO多路复用 一句话解释:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力. 2. 解决什么问题 说在前头 应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑, ...
- Linux中的多路IO转接,转载
linux系统对于多路i/o转接提供了几个强大的函数,但是这些函数各有优缺点,参照网上的资料以及自己的测试,总结如下: 首先看一个程序的例子: #include <time.h&g ...
- 一文看懂IO多路复用
本文首发在 技术成长之道 博客,访问 hechen0.com 查看更多,或者微信搜索「技术成长之道」关注我的公众号,或者扫描下方二维码关注公众号获得第一时间更新通知! 本文让你理解 什么是IO多路复用 ...
最新文章
- linux 生成dll文件,Linux和Windows平台 动态库.so和.dll文件的生成
- linux webservice服务器端,Linux查看资源使用情况 webservice服务端口监控
- JavaWeb总结(六)
- springboot session默认失效时间_Spring Boot 整合 Redis,用起来真简单
- cogs 1456. [UVa 10881,Piotr's Ants]蚂蚁
- 小学一年级第一次上计算机课,小学一年级上册信息技术教案【三篇】
- JavaScript(JS)中与正则表达式有关的方法介绍
- calc() ---一个会计算的css属性
- c++面试常考的知识点汇总
- 计算机程序的建立命令,数控车床编程指令 编程由一系列的指令组成
- SQL server 数据库基础知识之数据类型
- 智能算法---模拟退火搜索函数最小值
- 一张正面人脸照片,3D真人头像毫秒级重建。
- 软件体系结构风格整理
- 基于Forest实践|如何更优雅的统一处理请求签名
- Alphabetic Removals(水题)
- Cloudera Manager详细安装教程
- cmd 删除系统垃圾文件
- 希腊神话中的爱情悲剧
- 爬取 bilibili 弹幕数据
热门文章
- 大咖来信 | 张亚勤@2018:终日“闭关”读论文,思考终极算法
- 为AI芯片铺路?原三星半导体周军加盟Rokid
- Docker动荡在继续:创始人兼CTO离职
- 问题记录——com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure...
- 【344天】我爱刷题系列103(2018.01.15)
- shell 命令进阶(三)
- swift 笔记 (十四) —— 构造过程
- Cordova webapp实战开发:(2)认识一下Cordova
- DNS服务器配置之前传------基础知识普及
- 开始学习openlayer