3

私は定期的に(タイマーで)いくつかのデータストレージをチェックするアプリケーションを持っています。
このような:

#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/fcntl.h>
#include <unistd.h>

// EPOLL & TIMER
#include <sys/epoll.h>
#include <sys/timerfd.h>

int main(int argc, char **argv)
{
    /* epoll instance */
    int efd = epoll_create1(EPOLL_CLOEXEC);

    if (efd < 0)
    {
        std::cerr << "epoll_create error: " << strerror(errno) << std::endl;
        return EXIT_FAILURE;
    }

    struct epoll_event ev;
    struct epoll_event events[128];

    /* timer instance */
    int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);

    struct timespec ts;
    // first expiration in 3. seconds after program start
    ts.tv_sec = 3;
    ts.tv_nsec = 0;

    struct itimerspec new_timeout;
    struct itimerspec old_timeout;

    bzero(&new_timeout, sizeof(new_timeout));
    bzero(&old_timeout, sizeof(old_timeout));

    // value
    new_timeout.it_value = ts;

    // no interval;
    // timer will be armed in epoll_wait event trigger
    new_timeout.it_interval.tv_sec =
    new_timeout.it_interval.tv_nsec = 0;

    // Add the timer descriptor to epoll.
    if (tfd != -1)
    {
        ev.events = EPOLLIN | EPOLLERR /*| EPOLLET*/;
        ev.data.ptr = &tfd;
        epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev);
    }

    int flags = 0;
    if (timerfd_settime(tfd, flags, &new_timeout, &old_timeout) < 0)
    {
       std::cerr << "timerfd_settime error: " << strerror(errno) << std::endl;
    }

    int numEvents = 0;
    int timeout = 0;
    bool checkTimer = false;
    while (1)
    {
        checkTimer = false;
        numEvents = epoll_wait(efd, events, 128, timeout);
        if (numEvents > 0)
        {
            for (int i = 0; i < numEvents; ++i)
            {
                if (events[i].data.ptr == &tfd)
                {
                    std::cout << "timeout" << std::endl;
                    checkTimer = true;
                }
            }
        }
        else if(numEvents == 0)
        {
            continue;
        }
        else
        {
            std::cerr << "An error occured: " << strerror(errno) << std::endl;
        }

        if (checkTimer)
        {
            /* Check data storage */
            uint64_t value;
            ssize_t readBytes;
            //while ( (readBytes = read(tfd, &value, 8)) > 0)
            //{
            //    std::cout << "\tread: '" << value << "'" << std::endl;
            //}
            itimerspec new_timeout;
            itimerspec old_timeout;
            new_timeout.it_value.tv_sec = rand() % 3 + 1;
            new_timeout.it_value.tv_nsec = 0;
            new_timeout.it_interval.tv_sec =
            new_timeout.it_interval.tv_nsec = 0;
            timerfd_settime(tfd, flags, &new_timeout, &old_timeout);
        }
    }

    return EXIT_SUCCESS;
}

これは私のアプリの簡単な説明です。各タイムアウト タイマーの後、各タイムアウトで異なる値を再設定する必要があります。

質問は次のとおりです。

  1. EPOLLET フラグ付きの epoll (epoll_ctl) に timerfd を追加する必要がありますか?
  2. 各タイムアウト後に timerfd を読み取る必要がありますか?
  3. epoll_wait を無限に (タイムアウト = -1) する必要がありますか?
4

2 に答える 2

5

これは、エッジ トリガーまたはレベル トリガーの 2 つのモードのいずれかで実行できます。エッジ トリガー ルートを選択した場合は、パスする必要があり、各ウェイクアップ後EPOLLETに を読み取る必要はありません。timerfdからイベントを受け取ったということは、epoll1 つ以上のタイムアウトが発生したことを意味します。必要に応じて を読み取ると、最後に読み取ってからtimerfd発生したタイムアウトの数が返されます。

レベル トリガー ルートを選択した場合、 を渡す必要はありませんが、ウェイクアップごとにを読む必要EPOLLETがあります。そうしないと、タイムアウトになるまですぐに再び起こされます。timerfd

タイムアウトまたは正の値として渡す必要があり-1ます。epoll例のようにを渡す0と、スリープ状態になることはなく、タイムアウトが発生するのを待ってスピンするだけです。それはほぼ確実に望ましくない動作です。

于 2012-09-19T09:48:57.220 に答える