曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 10864|回复: 0
打印 上一主题 下一主题

pselect() | 防止信号干扰的增强型 select()

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-3-28 18:10:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
pselect() 函数的原型是:
[C++] 纯文本查看 复制代码
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                   fd_set *exceptfds, const struct timespec *timeout,
                   const sigset_t *sigmask);

它和 select() 函数基本相同,区别在于两个不同的参数,一个是 struct timespec *timeout,另一个是 sigset_t *sigmask 。

关于 select() 函数可参考:http://www.groad.net/bbs/read.php?tid-1064.html

struct timespec 结构定义为:
[C++] 纯文本查看 复制代码
  struct timespec {
               long    tv_sec;         /* seconds */
               long    tv_nsec;        /* nanoseconds */
           };

其中的时间表示秒和纳秒。和 select() 不同,每次超时后,pselect() 并不会去修改这个时间参数,也就是说,没有必要再次对这个时间参数进行初始化。

对于最后一个参数 sigmask 表示信号屏蔽掩码,关于信号屏蔽掩码以及操作函数参考(http://www.groad.net/bbs/read.php?tid-922.html)。
当使用该参数时,也就相当于将 select() 函数写成下列的形式:
[C++] 纯文本查看 复制代码
sigset_t origmask;

           sigprocmask(SIG_SETMASK, &sigmask, &origmask);
           ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
           sigprocmask(SIG_SETMASK, &origmask, NULL);


使用 pselect() 函数一个最大的原因正是它可以防止信号的干扰。比如说,如果你只是使用 select() 函数,在超时时间内很可能还会受到时钟信号(SIGALARM)
的打断,从而影响 select() 的正常使用。

下面引用网上的一篇博文以更具体的说明此函数的应用:
            
很久以来,同事写的一个模块,与串口收发数据的时候,SELECT()函数等待的时间长点,就会被模块里设置的时钟信号打断,最近看到了一个新的函数pselect(),研究了一把,收获不小!!
现在发现,SELECT()函数等待的这段时间内不想被别的信号打断的方法有两
其一:
用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;
   structsigaction act;

//set SIGALRM signal handler
   act.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 sigset
   if(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)
               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);
}

void
sig_int(int signo)
{
       char    s[] ="received";

psignal(signo, s);
return;
}

void
err_sys(const char *p_error)
{
       perror(p_error);

exit(1);
}

上段代码如果没有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       sigmask;
       ssize_t        nread;
       char           buf[BUFFSIZE];

sigset_t sigset;
   structsigaction act;

//set SIGALRM signal handler
   act.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 sigset
   if(sigemptyset(&sigset) == -1)
    err_sys("sigemptyet");
   if(sigaddset(&sigset, SIGALRM) == -1)
    err_sys("sigaddset");

//block SIGALRMsignal   
   if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -1)
    err_sys("sigprocmask");

//generate SIGALRM signal
   alarm(1);   
       FD_ZERO(&rset);
       FD_SET(STDIN_FILENO, &rset);
       maxfdp1 = STDIN_FILENO + 1;
       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);
}

void
sig_int(int signo)
{
       char    s[] ="received";

psignal(signo, s);
return;
}

void
err_sys(const char *p_error)
{
       perror(p_error);

exit(1);
}


同样,上段代码如果没有CTRL+C送上一个SIGINT信号,将永远阻塞在与用户的交互上,ALARM产生的SIGALRM信号永远打断不了SELECT,ALARM信号被成功屏蔽.
                                    
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:34 , Processed in 0.079654 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表