免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6999 | 回复: 13
打印 上一主题 下一主题

[Linux] [结贴]可否用poll()完全替代select()? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-06-03 10:35 |只看该作者 |倒序浏览
本帖最后由 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了吧.

多谢。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
2 [报告]
发表于 2013-06-03 10:50 |只看该作者
都是用epoll的.

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
3 [报告]
发表于 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这样的库,它对这些都封装了,且对每个特定的系统都尽量使用系统中最优的方法。

论坛徽章:
0
4 [报告]
发表于 2013-06-03 13:44 |只看该作者
井蛙夏虫 发表于 2013-06-03 13:16
(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?
谢谢。

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
5 [报告]
发表于 2013-06-03 15:06 |只看该作者
回复 4# weichuang02
poll专门用作监听错误:  
POLLIN和POLLOUT都不指定应该可以(未测试,文档也未说明,你可以试试)。
exceptfds是否严格的对应poll的POLLNVAL的状况:
异常情况还有:
  1. POLLERR
  2.               An error has occurred on the device or stream. This flag is only
  3.               valid  in the revents bitmask; it shall be ignored in the events
  4.               member.

  5.        POLLHUP
  6.               The device has been disconnected. This  event  and  POLLOUT  are
  7.               mutually-exclusive;  a  stream can never be writable if a hangup
  8.               has occurred. However, this event and POLLIN, POLLRDNORM,  POLL‐
  9.               RDBAND, or POLLPRI are not mutually-exclusive. This flag is only
  10.               valid in the revents bitmask; it shall be ignored in the  events
  11.               member.

  12.        POLLNVAL
  13.               The  specified  fd  value is invalid. This flag is only valid in
  14.               the revents member; it shall ignored in the events member.
复制代码

论坛徽章:
0
6 [报告]
发表于 2013-06-03 17:22 |只看该作者
本帖最后由 weichuang02 于 2013-06-03 17:51 编辑
井蛙夏虫 发表于 2013-06-03 15:06
回复 4# weichuang02
poll专门用作监听错误:  
POLLIN和POLLOUT都不指定应该可以(未测试,文档也未说明 ...


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

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

(1) select版本的小程序:


  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <poll.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/select.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>

  9. int main()
  10. {
  11.     int pFd[2];
  12.     int ret=pipe(pFd);
  13.     if( ret == -1 )
  14.     {
  15.         fprintf( stderr, "poll error, %s/n", strerror( errno ) );
  16.         return 1;
  17.     }
  18.     write( pFd[1], "hello", 5 );

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

  20.     fd_set fds;
  21.     FD_ZERO( &fds );
  22.     FD_SET( pFd[ 0 ], &fds );
  23.     FD_SET( nfd, &fds );
  24.     FD_SET( 2000,&fds ); //无效的fd,如何被select算进了返回值? 我没有加入exceptfds啊
  25.     timeval timeout = { 0, 0 };
  26.     int retval = select( 2001, &fds, &fds, NULL, &timeout ); // none block
  27.     if( retval < 0 )
  28.     {
  29.         fprintf( stderr, "1st select error, %s/n", strerror( errno ) );
  30.         return 1;
  31.     }
  32.     else if( retval == 0 )
  33.     {
  34.         printf( "No event!" );
  35.         return 1;
  36.     }
  37.     printf( "1st select return=%d, pFd[0] is readable=%d\n", retval, FD_ISSET(pFd[ 0 ],&fds) );

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

  47.     return 0;
  48. }
复制代码
程序运行的结果是
1st select return=3, pFd[0] is readable=0
2nd select return=2 pFd[0] is readable=0

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

下面是poll版的:


  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <poll.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/eventfd.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>

  9. int main()
  10. {
  11.     int pFd[2];
  12.     int ret=pipe(pFd);
  13.     if( ret == -1 )
  14.     {
  15.         fprintf( stderr, "poll error, %s/n", strerror( errno ) );
  16.         return 1;
  17.     }
  18.     write( pFd[1], "hello", 5 );

  19.     struct pollfd poll_list[ 2 ];
  20.     poll_list[ 0 ].fd = open( "/tmp/my.txt", O_CREAT | O_CLOEXEC );
  21.     poll_list[ 1 ].fd = pFd[ 0 ];
  22.     poll_list[ 0 ].events = POLLNVAL;
  23.     poll_list[ 1 ].events = POLLNVAL;
  24.     int retval =  poll( poll_list, 2, 0 ); // don't wait
  25.     if( retval < 0 )
  26.     {
  27.         fprintf( stderr, "1st poll error, %s/n", strerror( errno ) );
  28.         return 1;
  29.     }
  30.     printf( "1st poll return=%d\n", retval );
  31.     printf( "1st fd[0].revents=0x%x,fd[1].revents=0x%x\n", poll_list[ 0 ].revents, poll_list[ 1 ].revents );
  32.     char buf[10]={ 0 };
  33.     read( pFd[ 0 ], buf, sizeof( buf ) );
  34.     retval =  poll( poll_list, 2, 0 ); // don't wait
  35.     if( retval < 0 )
  36.     {
  37.         fprintf( stderr, "2nd poll error, %s/n", strerror( errno ) );
  38.         return 1;
  39.     }
  40.     printf( "2nd poll return=%d\n", retval );
  41.     printf( "2nd fd[0].revents=0x%x,fd[1].revents=0x%x\n", poll_list[ 0 ].revents, poll_list[ 1 ].revents );
  42.     return 0;
  43. }
复制代码
运行结果是
1st poll return=0
1st fd[0].revents=0x0,fd[1].revents=0x0
2nd poll return=0
2nd fd[0].revents=0x0,fd[1].revents=0x0

我的程序有什么问题么?

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
7 [报告]
发表于 2013-06-03 17:38 |只看该作者
回复 6# weichuang02
select的fds是输出参数,你先把两个fds分开试试后,再说吧

   

论坛徽章:
0
8 [报告]
发表于 2013-06-03 18:13 |只看该作者
井蛙夏虫 发表于 2013-06-03 17:38
回复 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
       (more  precisely,  to  see  if  a  read  will 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的对象。
如何解释呢?

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
9 [报告]
发表于 2013-06-03 18:16 |只看该作者
回复 8# weichuang02
它们是那种相当于c++引用参数性质的参数,既作为输入参数,又会被函数修改用来输出的参数。
   

论坛徽章:
0
10 [报告]
发表于 2013-06-03 18:36 |只看该作者
井蛙夏虫 发表于 2013-06-03 18:16
回复 8# weichuang02
它们是那种相当于c++引用参数性质的参数,既作为输入参数,又会被函数修改用来输出的 ...


哦,那这样的话,为什么我的select例子程序里面,select()返回3呢? fd=2000是个非法fd,我并没有指定exceptfds,那么这个fd=2000既不是可写也不是可读的,为何算进了select返回值里面?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP