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);
返回:就绪描述字的个数,-超时,--出错

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(...)) < )
{
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)) < )
{
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);

例如

:sigset_t new, old, zero;
:
:sigemptyset(&zero);
:sigemptyset(&new);
:sigaddset(&new, SIGINT);
:sigprocmask(SIG_BLOCK, &new, old);//block SIGINT
:if (intr_flag)
: handle_intr();//handle the signal
:if ((nready = pselet(..., &zero)) < ){
: if (errno = EINTR){
: if (intr_flag)
: handle_intr();
: }
: ...
:}

如果没有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 屏蔽信号

  #include       <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFSIZE 80
void sig_int(int signo);
void err_sys(const char *p_error);
void sig_alrm(int signo)
{
char s[] ="receive";
psignal(signo, s);
return;
}
int
main(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 handler
act.sa_handler= sig_alrm;
if(sigemptyset(&act.sa_mask) ==-)
err_sys("sigemptyset");
act.sa_flags= ;
if(sigaction(SIGALRM, &act, NULL) == -)
err_sys("sigaction");
//initialize signal set and addition SIGALRM into sigset
if(sigemptyset(&sigset) == -)
err_sys("sigemptyet");
if(sigaddset(&sigset, SIGALRM) == -)
err_sys("sigaddset");
alarm();
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
maxfdp1 = STDIN_FILENO + ;
if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= )
//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)) == -)
err_sys("read error");
if (write(STDOUT_FILENO, buf, nread) != nread)
err_sys("write error");
}
exit();
}
void
sig_int(int signo)
{
char s[] ="received";
psignal(signo, s);
return;
}
void
err_sys(const char *p_error)
{
perror(p_error);
exit();
}

上段代码如果没有CTRL+C送上一个SIGINT信号,将永远阻塞在与用户的交互上,ALARM产生的SIGALRM信号永远打断不了PSELECT,ALARM信号被成功屏蔽

2 用sigprocmask 屏蔽信号。

 #include       <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFSIZE 80
void sig_int(int signo);
void err_sys(const char *p_error);
void sig_alrm(int signo)
{
char s[] ="receive";
psignal(signo, s);
return;
}
int
main(int argc, char **argv)
{
int maxfdp1;
fd_set rset;
sigset_t zeromask;
ssize_t nread;
char buf[BUFFSIZE];
sigset_t sigset;
struct sigaction act;
//set SIGALRM signal handler
act.sa_handler= sig_alrm;
if(sigemptyset(&act.sa_mask) ==-)
err_sys("sigemptyset");
if(sigemptyset(&zeromask) ==-)
err_sys("sigemptyset");
act.sa_flags= ;
if(sigaction(SIGALRM, &act, NULL) == -)
err_sys("sigaction");
//initialize signal set and addition SIGALRM into sigset
if(sigemptyset(&sigset) == -)
err_sys("sigemptyet");
if(sigaddset(&sigset, SIGALRM) == -)
err_sys("sigaddset");
//block SIGALRMsignal
if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -)
err_sys("sigprocmask");
//generate SIGALRM signal
alarm();
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
maxfdp1 = STDIN_FILENO + ;
if (select(maxfdp1, &rset, NULL, NULL, NULL)<= )
//if (pselect(maxfdp1, &rset, NULL, NULL, NULL, &zeromask)<= 0)
err_sys("pselect error");
if (FD_ISSET(STDIN_FILENO, &rset))
{
if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -)
err_sys("read error");
if (write(STDOUT_FILENO, buf, nread) != nread)
err_sys("write error");
}
exit();
}
void
sig_int(int signo)
{
char s[] ="received";
psignal(signo, s);
return;
}
void
err_sys(const char *p_error)
{
perror(p_error);
exit();
}

上段代码如果没有CTRL+C送上一个SIGINT信号,将永远阻塞在与用户的交互上,ALARM产生的SIGALRM信号永远打断不了PSELECT,ALARM信号被成功屏蔽

3 如果 上述code代码改成下面则无法屏蔽信号,因为我们使用zeromask,它不屏蔽任何信号

  #include       <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFSIZE 80
void sig_int(int signo);
void err_sys(const char *p_error);
void sig_alrm(int signo)
{
char s[] ="receive";
psignal(signo, s);
return;
}
int
main(int argc, char **argv)
{
int maxfdp1;
fd_set rset;
sigset_t zeromask;
ssize_t nread;
char buf[BUFFSIZE];
sigset_t sigset;
struct sigaction act;
//set SIGALRM signal handler
act.sa_handler= sig_alrm;
if(sigemptyset(&act.sa_mask) ==-)
err_sys("sigemptyset");
if(sigemptyset(&zeromask) ==-)
err_sys("sigemptyset");
act.sa_flags= ;
if(sigaction(SIGALRM, &act, NULL) == -)
err_sys("sigaction");
//initialize signal set and addition SIGALRM into sigset
if(sigemptyset(&sigset) == -)
err_sys("sigemptyet");
if(sigaddset(&sigset, SIGALRM) == -)
err_sys("sigaddset");
//block SIGALRMsignal
if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -)
err_sys("sigprocmask");
//generate SIGALRM signal
alarm();
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
maxfdp1 = STDIN_FILENO + ;
//if (select(maxfdp1, &rset, NULL, NULL, NULL)<= 0)
if (pselect(maxfdp1, &rset, NULL, NULL, NULL, &zeromask)<= )
err_sys("pselect error");
if (FD_ISSET(STDIN_FILENO, &rset))
{
if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -)
err_sys("read error");
if (write(STDOUT_FILENO, buf, nread) != nread)
err_sys("write error");
}
exit();
}
void
sig_int(int signo)
{
char s[] ="received";
psignal(signo, s);
return;
}
void
err_sys(const char *p_error)
{
perror(p_error);
exit();
}

4 仅仅使用select,不使用sigprocmask也无法屏蔽信号。

 #include       <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFSIZE 80
void sig_int(int signo);
void err_sys(const char *p_error);
void sig_alrm(int signo)
{
char s[] ="receive";
psignal(signo, s);
return;
}
int
main(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 handler
act.sa_handler= sig_alrm;
if(sigemptyset(&act.sa_mask) ==-)
err_sys("sigemptyset");
act.sa_flags= ;
if(sigaction(SIGALRM, &act, NULL) == -)
err_sys("sigaction");
//initialize signal set and addition SIGALRM into sigset
if(sigemptyset(&sigset) == -)
err_sys("sigemptyet");
if(sigaddset(&sigset, SIGALRM) == -)
err_sys("sigaddset");
alarm();
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
maxfdp1 = STDIN_FILENO + ;
//if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= 0)
if (select(maxfdp1, &rset, NULL, NULL, NULL) <= )
err_sys("pselect error");
if (FD_ISSET(STDIN_FILENO, &rset))
{
if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) == -)
err_sys("read error");
if (write(STDOUT_FILENO, buf, nread) != nread)
err_sys("write error");
}
exit();
}
void
sig_int(int signo)
{
char s[] ="received";
psignal(signo, s);
return;
}
void
err_sys(const char *p_error)
{
perror(p_error);
exit();
}

5 用pselect,但信号屏蔽参数为NULL, 同使用select一样,无法屏蔽信号

  #include       <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFSIZE 80
void sig_int(int signo);
void err_sys(const char *p_error);
void sig_alrm(int signo)
{
char s[] ="receive";
psignal(signo, s);
return;
}
int
main(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 handler
act.sa_handler= sig_alrm;
if(sigemptyset(&act.sa_mask) ==-)
err_sys("sigemptyset");
act.sa_flags= ;
if(sigaction(SIGALRM, &act, NULL) == -)
err_sys("sigaction");
//initialize signal set and addition SIGALRM into sigset
if(sigemptyset(&sigset) == -)
err_sys("sigemptyet");
if(sigaddset(&sigset, SIGALRM) == -)
err_sys("sigaddset");
alarm();
FD_ZERO(&rset);
FD_SET(STDIN_FILENO, &rset);
maxfdp1 = STDIN_FILENO + ;
//if (pselect(maxfdp1, &rset, NULL, NULL, NULL,&sigset) <= 0)
if (pselect(maxfdp1, &rset, NULL, NULL, NULL,NULL) <= )
//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)) == -)
err_sys("read error");
if (write(STDOUT_FILENO, buf, nread) != nread)
err_sys("write error");
}
exit();
}
void
sig_int(int signo)
{
char s[] ="received";
psignal(signo, s);
return;
}
void
err_sys(const char *p_error)
{
perror(p_error);
exit();
}

pselect 和 select的更多相关文章

  1. UNIX环境高级编程——I/O多路转接(select、pselect和poll)

    I/O多路转接:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回.在返回时,它告诉进程哪些描述符已准备好可以进行I/O. poll.pselect ...

  2. 高级I/O之I/O多路转接——pool、select

    当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中使用阻塞I/O: ) if (write(STDOUT_FILENO, buf, n) != n) err_sys("wri ...

  3. Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)

    Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ...

  4. UNP——第六章,多路转接IO——select

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ...

  5. I/O多路转接 --- UNIX环境高级编程

    I/O多路转接技术:先构造一张有关描述符的列表,然后调用一个函数,知道这些描述符中的一个已准备好进行I/O时,给函数才返回.在返回时,它告诉进程哪些描述符已准备好可以进行I/O. poll.selec ...

  6. 4.I/O复用以及基于I/O复用的回射客户端/服务器

    I/O复用:当一个或多个I/O条件满足时,我们就被通知到,这种能力被称为I/O复用. 1.I/O复用的相关系统调用 posix的实现提供了select.poll.epoll两类系统调用以及相关的函数来 ...

  7. Linux/UNIX先进I/O

    先进I/O 非阻塞IO 非阻塞I/O因此,我们可以称之为open.read和write这种I/O操作,而这些操作不会永久阻止.我们假设,该操作不能完成,然后调用立即返回一个错误.则表示该操作将继续作为 ...

  8. Oracle DBA管理包脚本系列(二)

    该系列脚本结合日常工作,方便DBA做数据管理.迁移.同步等功能,以下为该系列的脚本,按照功能划分不同的包.功能有如下: 1)数据库对象管理(添加.修改.删除.禁用/启用.编译.去重复.闪回.文件读写. ...

  9. Socket网络编程--聊天程序(4)

    上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理.对于多用户连接时,服务器会受不了的,而且还很消耗资源.据说有个select函数可以用,好像还很 ...

随机推荐

  1. java验证openssl生成的ssl证书和私钥是否匹配

    最近有一个需求上传ssl证书和私钥,但是上传之前需要验证ssl证书和私钥是否正确,其中的业务逻辑涉及到以下几点: 一.读取ssl证书,读取ssl证书公钥       要实现该功能比较简单,java里面 ...

  2. Codeforces Beta Round #7 A. Kalevitch and Chess 水题

    A. Kalevitch and Chess 题目连接: http://www.codeforces.com/contest/7/problem/A Description A famous Berl ...

  3. CROC 2016 - Elimination Round (Rated Unofficial Edition) D. Robot Rapping Results Report 二分+拓扑排序

    D. Robot Rapping Results Report 题目连接: http://www.codeforces.com/contest/655/problem/D Description Wh ...

  4. Vue学习记录-接口通信(数据请求)

    这一篇,把前两天实践的“数据请求”部分总结一下.从最终的结果来看,配置非常的简单,使用非常的简单,也非常的灵活,同时也存在一个很头疼的问题,这个问题可以解决,但是解释不了(功力尚浅). 选型 可选项: ...

  5. Python3的变化

    http://www.cnblogs.com/tips4python/archive/2011/05/31/2064290.html print 由一个语句(statement)变为一个函数 Pyth ...

  6. SqlServer收缩数据库语句

    ALTER DATABASE [Spacebuilder] SET RECOVERY SIMPLEDBCC SHRINKDATABASE([Spacebuilder], 0)ALTER DATABAS ...

  7. photoshop:制作sprite拼贴图片

    目标: 将 合并为一张图片: 第一步:制作动作,便于批处理和重复使用 首先随便新建空白文档录制动作,alt+F9 创建新动作->1.打开一个小图2.图像->模式->RGB(避免有的图 ...

  8. .NET:为什么不能在子类或外部发布C#事件

    背景 一个朋友问了一个问题:“为什么不能在子类或外部发布C#事件?”,我说我不知道,要看看生产的IL代码,下面我们看看. 测试 代码 using System; using System.Collec ...

  9. nolock的使用

    在SQL Server 2005数据库查询时,为了提高查询的性能,我们往往会在表后面加一个nolock,或者是with(nolock),让数据库在查询时不锁定表,从而提高查询的速度.本文我们就介绍SQ ...

  10. 利用StringUtils工具类进行String为空的判断

      利用工具类进行String类型数据的非空判断,让自己的项目代码变得更加的简洁明了.   判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0   下面是 St ...