6

我想使用it_intervalofnewValue来设置超时的间隔。
但在我的示例中,我只能打印timeout 一次
发生了什么?如何设置间隔?

这是我的代码:

int main()
{
int efd =epoll_create(256);             
setnonblock(efd);
struct epoll_event ev,events[256];

int tfd;//timer fd

if((tfd= timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0)
  cout<<"timerfd create error"<<endl;

struct itimerspec newValue;
struct itimerspec oldValue;
bzero(&newValue,sizeof(newValue));  
bzero(&oldValue,sizeof(oldValue));
struct timespec ts;
ts.tv_sec = 5;
ts.tv_nsec = 0;

    //both interval and value have been set
    newValue.it_value = ts; 
    newValue.it_interval = ts;
    if( timerfd_settime(tfd,0,&newValue,&oldValue) <0)
    {
        cout<<"settime error"<<strerror(errno)<<endl;
    }   

    ev.data.fd = tfd;
    ev.events = EPOLLIN | EPOLLET;

    if( epoll_ctl(efd,EPOLL_CTL_ADD,tfd,&ev) < 0)
        cout<<"epoll_ctl error"<<endl;

    int num = 0;
    while(1)
    {
       if((num=epoll_wait(efd,events,256,1000)) > 0)
       {//justice
            for(int i=0;i<num;i++)
            {
                if(events[i].data.fd == tfd)
                {
                    cout<<"timeout"<<endl;
                }
        }       
    }
    }   
return 0;
}
4

1 回答 1

19

这是因为您使用的是 EPOLLET 而不是读取()生成到 tfd 中的数据。计时器的到期“写入”了需要读取的 8 个字节的数据:您确实需要读取它。打印“超时”时添加:

uint64_t value;
read(tfd, &value, 8);

更详细地说:EPOLLET 要求边缘触发,这意味着 epoll_wait() 只会在文件描述符 tfd 上说一次“数据准备好输入”,直到您读取该数据。换句话说,只要您没有读取该数据,将来对 epoll_wait() 的调用就不会再次返回相同的描述符。这种行为对普通套接字很有用,例如,如果您在主线程中执行 epoll_wait(),请注意一些数据已准备好,然后启动另一个线程来读取它。主线程立即返回 epoll_wait()。但是我们不希望它立即再次唤醒,即使文件描述符中的数据可能还没有被读取。

请注意,我猜您没有 EPOLLET 的示例也是错误的,不同的是:因为您不读取(),所以 tfd 在初始延迟后始终是可读的,因此它会在初始延迟后尽快打印“超时”过期。

于 2012-09-02T12:44:39.993 回答