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. [QSCOJ39]喵哈哈村的代码传说 第五章 找规律

    题目大意: 给你n堆排,两人轮流对其中一堆牌进行以下操作之一: 1.从这堆牌中取出任意数量的牌: 2.将这这堆牌分为任意大小的3堆牌. 不能操作者负. 问先手是否有必胜策略. 思路: 尝试构造sg函数 ...

  2. [AtCoder-ARC073F]Many Moves

    题目大意: 有一排n个格子和2枚硬币. 现在有q次任务,每一次要你把其中一枚硬币移到x的位置上,移动1格的代价是1. 两枚硬币不能同时移动,任务必须按次序完成. 现在告诉你两枚硬币初始状态所在的位置a ...

  3. Codeforces Round #346 (Div. 2) E. New Reform dfs

    E. New Reform 题目连接: http://www.codeforces.com/contest/659/problem/E Description Berland has n cities ...

  4. C# 时间戳与当前时间互相转换

    时间戳: Unix时间戳(Unix timestamp),或称Unix时间(Unix time).POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日 ...

  5. Java中应该返回零长度数组或空集合,而不是返回null(转)

    说明:为了避免在数组和集合的获取上增加null的判断,同时也能减少不必要的空指针异常,通常会在业务返回零数组或空集合. 方法: 1.数组: 定义全局静态常量来减少内存开销:private static ...

  6. iOS 热更新方案 - lance的专栏 - 博客频道 - CSDN.NET

    iOS 热更新方案 - lance的专栏 - 博客频道 - CSDN.NET Weex

  7. ASCII表 基本记忆 -- C

    /* ASCII表规则记忆 我们仅仅要记住了一个字母或数字的 ASCII 码 (比如记住 A 为 65 , 0 的 ASCII 码为 48 ), 知道对应的大写和小写字母之间差 32. 0 -- 32 ...

  8. iptables学习与研究(使用LOG记录失败日志)

    原文地址: http://blog.csdn.net/fafa211/article/details/2307581 通常情况下,iptables的默认政策为DROP,不匹配的数据包将被直接丢弃.但在 ...

  9. Linux的进程优先级NI和PR

    为什么要有进程优先级? 这似乎不用过多的解释,毕竟自从多任务操作系统诞生以来,进程执行占用cpu的能力就是一个必须要可以人为控制的事情.因为有的进程相对重要,而有的进程则没那么重要. 进程优先级起作用 ...

  10. Appium+python自动化12-appium元素定位

    前言 appium定位app上的元素,可以通过id,name.class这些属性定位到 一.id定位 1.appium的id属性也就是通过UI Automator工具查看的resource-id属性