关于select函数的一些疑问

Wolf_cgl 2016-06-24 12:19:33
  想做一个监控文件的小功能,文件是FIFO类型,可能被写入0或者1,我要做的就是监控这个文件,如果被更新了就把值读出来。
  用到select函数,但出现一些不太好理解的现象。

  1. 每次select之前,好像都需要设置一下timeout时间,比如下面程序如果把时间设置放在while前,那么将会狂打印"once"。
  2. 程序执行时,一开始“once"的打印差不多1s一次。在另一个终端输入:echo -n 0 > has_sd_card 之后,“once"有事疯狂打印了,timeout设置失效了?还是说我的echo -n 0 > has_sd_card导致stdin可读了,但是已经被重定向到文件了,想不明白。

  求解答

程序源码如下:

// Linux include
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <stdio.h>
#include <iostream>

int main()
{
int mdevFd = -1;
mdevFd = open("has_sd_card", O_RDONLY|O_NONBLOCK);
if (mdevFd < 0) {
std::cout << "Open file failed." << std::endl;
return -1;
}
std::cout << mdevFd << std::endl;

int ret;
char value;
fd_set rd;
struct timeval tv;

while (true) {
FD_ZERO(&rd);
FD_SET(mdevFd, &rd);
tv.tv_sec = 0;
tv.tv_usec = 1000000; /* timeout 1000 ms */
std::cout << "1" << std::endl;
ret = select(mdevFd + 1, &rd, NULL, NULL, &tv);
std::cout << "2" << std::endl;
if (ret > 0 && read(mdevFd, &value, sizeof(char)) > 0) {
std::cout << "File updated, value = " << value << std::endl;
}
std::cout << "once" << std::endl;
}

close(mdevFd);
return 0;
}

...全文
234 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
Wolf_cgl 2016-07-05
  • 打赏
  • 举报
回复
引用 8 楼 CNL 的回复:
如果还要监控,close之后再重新open就行了
close之后是可以,只是频繁打开文件,用来做监控的话就不太好了,或许该考虑换其他方法。
zrlw 2016-07-03
  • 打赏
  • 举报
回复
如果还要监控,close之后再重新open就行了
zrlw 2016-07-02
  • 打赏
  • 举报
回复
因为你没有处理read返回0,返回0时要close文件,否则你就飞了
zhxingway 2016-07-01
  • 打赏
  • 举报
回复
干嘛要用select啊。 定时获取下文件的更新时间不是更好? 如果有更新再去读。
Wolf_cgl 2016-06-30
  • 打赏
  • 举报
回复
如果在一个描述符上碰到了文件尾端,则select会认为该描述符是可读。 ----这个有办法做到下次select的时候,在没有可读数据时认为它不可读么?
renwotao2009 2016-06-30
  • 打赏
  • 举报
回复

while (true) {
        FD_ZERO(&rd);
        FD_SET(mdevFd, &rd);
        tv.tv_sec   = 0;
        tv.tv_usec  = 1000000;    /* timeout 1000 ms */
        std::cout << "1" << std::endl;
        ret = select(mdevFd + 1, &rd, NULL, NULL, &tv);
        std::cout << "2" << std::endl;
        if (ret > 0 && read(mdevFd, &value, sizeof(char)) > 0) {
            std::cout << "File updated, value = " << value << std::endl;
        }
        std::cout << "once" << std::endl;
    }
如果在一个描述符上碰到了文件尾端,则select会认为该描述符是可读。然后调用read,它返回0,这是UNIX系统指示到达文件尾端的方法。注:这不是异常。
Wolf_cgl 2016-06-30
  • 打赏
  • 举报
回复
嗯,timeout清零重置好理解。然后是第二个问题,在文件不可读的时候,once的打印是一秒一次,成可读之后,疯狂打印once是怎么回事? 因为在while循环里边,timeout已经重置了,应该不是失效。文件是fifo的,read之后文件应该就不会再是可读了吧,但结果是可读的,只是read不出数据了。可以用下面的打印测试: std::cout << "Before select:" << *((int*)(&rd)) << std::endl; ret = select(fd + 1, &rd, NULL, NULL, &tv); std::cout << "After select:" << *((int*)(&rd)) << std::endl; 一开始, Before select:8 After select:0 但是写入文件之后,就一直是 Before select:8 After select:8 就算数据被read读取掉了也是这个状态,从这里看的话一直刷once是可以理解的,但这里不好理解的就是select的工作方式了。
codingMozart 2016-06-25
  • 打赏
  • 举报
回复
linux下,select会把timeout清零,所以每次进入select前都要重新初始化timeout
图灵转世 2016-06-25
  • 打赏
  • 举报
回复
我也犯过同样的错误。

23,217

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧