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. OpenSSL Heartbleed “心脏滴血”漏洞简单攻击示例

    OpenSSL Heartbleed漏洞的公开和流行让许多人兴奋了一把,也让另一些人惊慌了一把. 单纯从攻击的角度讲,我已知道的,网上公开的扫描工具有: 1.  Nmap脚本ssl-heartblee ...

  2. bzoj1036 count 树链剖分或LCT

    这道题很久以前用树链剖分写的,最近在学LCT ,就用LCT再写了一遍,也有一些收获. 因为这道题点权可以是负数,所以在update时就要注意一下,因为平时我的0节点表示空,它的点权为0,这样可以处理点 ...

  3. LCA(倍增在线算法) codevs 2370 小机房的树

    codevs 2370 小机房的树 时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点, ...

  4. Codeforces Round #301 (Div. 2) A. Combination Lock 暴力

    A. Combination Lock Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/540/p ...

  5. 搭建MSSM框架(Maven+Spring+Spring MVC+MyBatis)

    https://github.com/easonjim/ssm-framework 先欠着,后续再进行讲解: 一.Spring内核集成 二.Spring MVC集成 三.MyBatis集成 四.代码生 ...

  6. 在pcDuino上使用蓝牙耳机玩转音乐

    1.资源 pcDuino板子一个.HDMI to VGA线一条.电源线一条.USB hub一个.显示器.鼠标.键盘.蓝牙适配器.蓝牙耳机. 2.资源已经到位,让我们开始吧 1.在ubuntu上安装蓝牙 ...

  7. HDU 4669 Mutiples on a circle (2013多校7 1004题)

    Mutiples on a circle Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Oth ...

  8. PHP session过期机制和配置

    问题:使用PHP session时会遇到明明超过了session过期时间,但session依然完好无损的活着,让人头大. 其实仔细看一下php.ini关于PHP session回收机制就一目了然了. ...

  9. Ubuntu中升极下载4.2内核

    http://tech.hexun.com/2015-09-11/179027013.html 从这段话中所表达出的意思可以了解,Linux Kernel 4.3版本已经开始进行,Linus Torv ...

  10. unsigned int与int相加的问题-----C/C++小知识 区别

    http://blog.csdn.net/thefutureisour/article/details/8147277 #include "stdafx.h" int _tmain ...