weichuang02 发表于 2013-06-03 10:35

[结贴]可否用poll()完全替代select()?

本帖最后由 weichuang02 于 2013-06-04 10:50 编辑

之前在版上和各位大侠讨论了poll函数效率为什么比select要高。还有2点想要弄清楚的:

(1)这两个函数的用法是稍有不同的,select区分了readfds,writefds,exeptfds,而poll不区分,为什么有这样的不同呢?
(2)难道有什么工作是select可以做到而poll做不到的?exceptfds是否严格的对应poll的POLLNVAL的状况?
    如果select能做的poll都能做,那么是不是任何情况都推荐使用select而不是poll? linux各种软件的源代码里面也应该用poll/ppoll/epoll而不是select了吧.

多谢。

linux_c_py_php 发表于 2013-06-03 10:50

都是用epoll的.

井蛙夏虫 发表于 2013-06-03 13:16

(1)poll的pollfd结构也区分了read,write和exception。
(2)同时存在poll和select,是因为在以前的时候,有些系统只支持select,不支持poll(现在应该很少了)。
在同时有poll和select,且仅有它们的系统中,应当尽量使用poll而不是select。
在linux中,有epoll,但它是linux特有的,别的系统没有,在跨平台的程序中不通用。但在linux中,应当尽量使用它。
实际使用,你可以看看libevent这样的库,它对这些都封装了,且对每个特定的系统都尽量使用系统中最优的方法。

weichuang02 发表于 2013-06-03 13:44

井蛙夏虫 发表于 2013-06-03 13:16 static/image/common/back.gif
(1)poll的pollfd结构也区分了read,write和exception。
(2)同时存在poll和select,是因为在以前的时候,有 ...

我对poll参数的理解是,能观察某个fd,在调用的时候指定events为POLLIN|POLLOUT,返回后的revents才有POLLNVAL.
为什么你说“pollfd结构也区分了read,write和exception。”?似乎并没有fd是能给poll专门用作监听错误的吧?

我猜想你是说events指定为POLLNVAL就是等同于select的exceptfds?
谢谢。

井蛙夏虫 发表于 2013-06-03 15:06

回复 4# weichuang02
poll专门用作监听错误:
POLLIN和POLLOUT都不指定应该可以(未测试,文档也未说明,你可以试试)。
exceptfds是否严格的对应poll的POLLNVAL的状况:
异常情况还有:POLLERR
            An error has occurred on the device or stream. This flag is only
            validin the revents bitmask; it shall be ignored in the events
            member.

       POLLHUP
            The device has been disconnected. ThiseventandPOLLOUTare
            mutually-exclusive;astream can never be writable if a hangup
            has occurred. However, this event and POLLIN, POLLRDNORM,POLL‐
            RDBAND, or POLLPRI are not mutually-exclusive. This flag is only
            valid in the revents bitmask; it shall be ignored in theevents
            member.

       POLLNVAL
            Thespecifiedfdvalue is invalid. This flag is only valid in
            the revents member; it shall ignored in the events member.

weichuang02 发表于 2013-06-03 17:22

本帖最后由 weichuang02 于 2013-06-03 17:51 编辑

井蛙夏虫 发表于 2013-06-03 15:06 static/image/common/back.gif
回复 4# weichuang02
poll专门用作监听错误:
POLLIN和POLLOUT都不指定应该可以(未测试,文档也未说明 ...

我发现select和poll还是有点区别的,我写了两个小的例子程序,做了相似的事情,也就是先创建一个管道,写入,调用select或者poll,读出,再调用select或poll

发现结果不一样。
select版,当写端pFd被写入一写数据的时候,select认为它的读端pFd可读状态是false。奇怪。
而poll的版本,对于两个都是有效的fd,竟然返回值是0。明明写端已经有数据了啊。

(1) select版本的小程序:

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int pFd;
    int ret=pipe(pFd);
    if( ret == -1 )
    {
      fprintf( stderr, "poll error, %s/n", strerror( errno ) );
      return 1;
    }
    write( pFd, "hello", 5 );

    int nfd = open( "/tmp/my.txt", O_CREAT | O_CLOEXEC );

    fd_set fds;
    FD_ZERO( &fds );
    FD_SET( pFd[ 0 ], &fds );
    FD_SET( nfd, &fds );
    FD_SET( 2000,&fds ); //无效的fd,如何被select算进了返回值? 我没有加入exceptfds啊
    timeval timeout = { 0, 0 };
    int retval = select( 2001, &fds, &fds, NULL, &timeout ); // none block
    if( retval < 0 )
    {
      fprintf( stderr, "1st select error, %s/n", strerror( errno ) );
      return 1;
    }
    else if( retval == 0 )
    {
      printf( "No event!" );
      return 1;
    }
    printf( "1st select return=%d, pFd is readable=%d\n", retval, FD_ISSET(pFd[ 0 ],&fds) );

    char buf={ 0 };
    read( pFd[ 0 ], buf, sizeof( buf ) );
    retval =select( 2001, &fds, &fds, NULL, &timeout );
    if( retval < 0 )
    {
      fprintf( stderr, "2nd select error, %s/n", strerror( errno ) );
      return 1;
    }
    printf( "2nd select return=%d, pFd is readable=%d\n", retval, FD_ISSET(pFd[ 0 ],&fds) );

    return 0;
}
程序运行的结果是
1st select return=3, pFd is readable=0
2nd select return=2 pFd is readable=0

很奇怪,write了管道pFd之后,读端的readable竟然是false. 而且对于无效的fd=2000,select返回的时候也算进了返回值里面?

下面是poll版的:

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int pFd;
    int ret=pipe(pFd);
    if( ret == -1 )
    {
      fprintf( stderr, "poll error, %s/n", strerror( errno ) );
      return 1;
    }
    write( pFd, "hello", 5 );

    struct pollfd poll_list[ 2 ];
    poll_list[ 0 ].fd = open( "/tmp/my.txt", O_CREAT | O_CLOEXEC );
    poll_list[ 1 ].fd = pFd[ 0 ];
    poll_list[ 0 ].events = POLLNVAL;
    poll_list[ 1 ].events = POLLNVAL;
    int retval =poll( poll_list, 2, 0 ); // don't wait
    if( retval < 0 )
    {
      fprintf( stderr, "1st poll error, %s/n", strerror( errno ) );
      return 1;
    }
    printf( "1st poll return=%d\n", retval );
    printf( "1st fd.revents=0x%x,fd.revents=0x%x\n", poll_list[ 0 ].revents, poll_list[ 1 ].revents );
    char buf={ 0 };
    read( pFd[ 0 ], buf, sizeof( buf ) );
    retval =poll( poll_list, 2, 0 ); // don't wait
    if( retval < 0 )
    {
      fprintf( stderr, "2nd poll error, %s/n", strerror( errno ) );
      return 1;
    }
    printf( "2nd poll return=%d\n", retval );
    printf( "2nd fd.revents=0x%x,fd.revents=0x%x\n", poll_list[ 0 ].revents, poll_list[ 1 ].revents );
    return 0;
}
运行结果是
1st poll return=0
1st fd.revents=0x0,fd.revents=0x0
2nd poll return=0
2nd fd.revents=0x0,fd.revents=0x0

我的程序有什么问题么?

井蛙夏虫 发表于 2013-06-03 17:38

回复 6# weichuang02
select的fds是输出参数,你先把两个fds分开试试后,再说吧

   

weichuang02 发表于 2013-06-03 18:13

井蛙夏虫 发表于 2013-06-03 17:38 static/image/common/back.gif
回复 6# weichuang02
select的fds是输出参数,你先把两个fds分开试试后,再说吧

man上面写的是这3个都是输入参数啊:

Three independent sets of file descriptors are watched.Those listed in readfds will be watched to see if characters become available for reading
       (moreprecisely,toseeifareadwill not block; in particular, a file descriptor is also ready on end-of-file), those in writefds will be
       watched to see if a write will not block, and those in exceptfds will be watched for exceptions.

都是watch的对象。
如何解释呢?

井蛙夏虫 发表于 2013-06-03 18:16

回复 8# weichuang02
它们是那种相当于c++引用参数性质的参数,既作为输入参数,又会被函数修改用来输出的参数。
   

weichuang02 发表于 2013-06-03 18:36

井蛙夏虫 发表于 2013-06-03 18:16 static/image/common/back.gif
回复 8# weichuang02
它们是那种相当于c++引用参数性质的参数,既作为输入参数,又会被函数修改用来输出的 ...

哦,那这样的话,为什么我的select例子程序里面,select()返回3呢? fd=2000是个非法fd,我并没有指定exceptfds,那么这个fd=2000既不是可写也不是可读的,为何算进了select返回值里面?
页: [1] 2
查看完整版本: [结贴]可否用poll()完全替代select()?