select的使用

来源:互联网 发布:达达妈淘宝店是正品吗 编辑:程序博客网 时间:2024/05/07 21:42

                                                 select函数的一点使用心得    


select函数等待过程中,如果有信号产生,函数自动返回,并返回interruptsystem call值-1。在pselect函数等待过程中,如果有信号产生,函数是否返回依赖最后一个参数的设定,当设置为空时,同select。

 

在am中当系统有信号产生的时候,app_client.c的select会返回-1,i4_status< 0造成_thread_read_monitor退出,所以如果条件允许的话,可以忽略interrupt system call

 

#include<sys/select.h>

int select(int maxfdp1, fd_set *restrict readfds,fd_set*restrict writefds,

fd_set *restrict exceptfds, struct timeval *restricttvptr);

Returns: count of ready descriptors, 0 on timeout, -1 onerror

返回值:准备就绪的描述符数,若超时则返回0,若出错则返回-1

 

select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式:

FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位

FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真

FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位

FD_ZERO(fd_set *set);用来清除描述词组set的全部位

 

 运用这个函数时,我们要思考:

a.传向select的参数告诉内核什么?

1)我们所关心的描述符。

2)对于每个描述符,我们所关心的状态。(是否读一个给定的描述符?是否想写一个给定的描述符?是否关心一个描述符的异常状态?)。

3)愿意等待多长时间。(可以永远等待,等待一个固定时间量,或完全不等待)。

 

b.从select返回时,内核告诉我们什么?

1)已准备好的描述符的数量。

2)对于读、写或异常这三个状态中的每一个,哪些描述符已准备好。

使用这些返回信息,就可以调用相应的I/O函数(一般是read或write),并且确知该函数不会被阻塞。

 

c.select的参数

struct timeval:是愿意等待的时间。

struct timeval {

    longtv_sec;        

longtv_usec;     

};

tvptr==NULL:永远等待。如果捕捉到信号则终端此无限期等待。

tvptr->tv_sec==0&&tvptr->tv_usec==0:完全不等待。测试所有指定的描述符并立即返回。

tvptr->tv_sec!=0||tvptr->tv_usec!=0:等待指定的秒数和微秒数。当指定的描述符之一准备好,或者指定的时间值已经超过时立即返回。

 

readfds,writefds,exceptfds:指向描述符集的指针。分别为可读、可写、异常条件的各个描述符集。每个描述符集存放在一个FD_SET数据类型中。这种数据类型为每一可能的描述符保持了一位。

 

对FD_SET数据类型可以进行的处理是:分配一个这种类型的变量;将这种类型的变量赋予同类型的另一个变量;或对于这种类型的变量使用下列4个函数中的一个:

 

#include <sys/select.h>intFD_ISSET(int fd, fd_set *fdset);Returns: nonzero if fd is in set, 0otherwise

 

void FD_CLR(int fd, fd_set *fdset);

void FD_SET(int fd, fd_set *fdset);

void FD_ZERO(fd_set *fdset);

 

这些接口可以实现为宏或者函数。调用FD_CLR将指定fd_set变量位清除;调用FD_SET设置fd_set变量指定位;调用FD_ZERO将fd_set变量所有位设置为0.

 

声明了一个描述符集后,必须用FD_ZERO清除其所有位,然后再其中设置我们关心的所有位。常用操作如下:

 

fd_set   rset;

int     fd;

FD_ZERO(&rset);

FD_SET(fd, &rset);

FD_SET(STDIN_FILENO, &rset);

 

从select返回时,用FD_ISSET测试该集中的任何一个给定位是否仍旧被设置,如果被设这,则说明描述度准备好,可以进行操作了。

 

   if (FD_ISSET(fd,&rset)){      ...   }

 

select的中间3个参数中的任意一个或者全部都可以是空指针,这表示相应状态并不关心。如果所有三个指针都是空指针,则select提供了较sleep更精确的计时器。

 

 

 

maxfdp1:最大描述符+1。在三个描述符集中找出最大描述符编号值,然后+1。相应操作:

 

int fd1,fd2,fd3,maxfd,maxfd1;

 

if(fd1>fd2)

 {

      max_fd=fd1;

 }

 else

 {

   max_fd=fd2;

 }

 

if(max_fd<fd3)

  max_fd=fd3;

 

maxfd1=maxfd+1;

 

为什么要加1,是因为描述符编号是从0开始的。

 

 

d.select的返回值

 

返回-1:表示出错。

返回0:表示没有描述符准备好。

返回正值:表示已经准备好的描述符数。

 

pselect函数

 

#include <sys/select.h>

 

int pselect(int maxfdp1, fd_set *restrict readfds, fd_set*restrict writefds,

 

fd_set*restrict exceptfds, const struct timespec *restricttsptr, const sigset_t *restrict sigmask);

 

Returns: count of ready descriptors, 0 on timeout, 1 onerror

 

pselect与select的不同之处:

 

1)select超时值用timeval指定,但pselect用timespec指定。timeval是秒和微妙,timespec是秒和纳秒所以timespec提供了比timeval更准确的超时时间。

 

2)pselect的超时值被声明为const,这就保证调用pselect不会改变此值。

 

3)对于pselect可以使用一个可选的信号屏蔽字。若sigmask为空,那么在与信号有关的方面,二者相同;若sigmask指向一信号屏蔽字,在调用pselect时,以原子操作的方式安装该信号屏蔽字。在返回时恢复以前的信号屏蔽字。

下面是linux环境下select的一个简单用法

用来循环读取键盘输入

#include     <stdio.h>
#include <erron.h>
#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>
int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
{
timeout.tv_sec=1;
timeout.tv_usec=0;
FD_ZERO(&readfd);
FD_SET(keyboard,&readfd);
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
if(FD_ISSET(keyboard,&readfd))
{
i=read(keyboard,&c,1);
if('\n'==c)
continue;
printf("hehethe input is %c\n",c);

if ('q'==c)
break;
}
}
}
用来循环读取键盘输入

0 0
原创粉丝点击