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多路复用 ...
最新文章
- 学习java三个技巧要知道!
- bigdecimal如何做除法_公务员行测朴素逻辑解题技巧—代入排除法
- 号称迄今为止最快,.NET6带来了什么?
- 2020年快手短视频直播电商营销增长宝典
- C语言里的几个拷贝函数memcpy、memset、strcpy、strncpy
- Linux下安装配置PHP环境(上)---Apache2
- 多元梯度下降法(2)--学习率α machine learning
- vb.net mysql 实例教程_VB.NET数据库编程基础教程(转载
- ListView分页显示数据
- 【Arduino创意】基于蜂鸣器制作摩尔斯电码生成器
- excel粘贴时出现故障_excel无法复制粘贴怎么办?告诉你解决方法
- Mybatis关联关系
- 手势识别(一)--手势基本概念和ChaLearn Gesture Challenge
- 51Nod 1463
- IDEA编译报错:java: 未报告的异常错误X; 必须对其进行捕获或声明以便抛出
- html5 制作书架展示 PHP,简单做出HTML5翻页效果文字特效
- YT8511H的原理图设计
- OpenGl法向量计算
- 【数量技术宅|金融数据分析系列分享】套利策略的价差序列计算,恐怕没有你想的那么简单
- tcp拥塞算法分析一(拥塞避免和慢启动)
热门文章
- 想让照片里的美女“回头”?清华MIT谷歌用AI帮你实现了
- 火爆GitHub:100天搞定机器学习编程(超赞信息图+代码+数据集)
- 数组常用方法:是否改变原数组
- 安卓Android Support Design Library——Snackbar
- 50 招教你防止黑客入侵,适用于入门小白到专业人员
- 我的MYSQL学习心得(十一) 视图
- Composer php 类库商店
- phpcms能做什么呢?有什么作用呢?
- dwz ajax session超时跳转登录页(struts2自定义阻碍器)
- [转]编程之美数组分割问题