eventfd接口

参考博客:https://www.cnblogs.com/developing/p/10887779.html

eventfd 实现线程事件通知机制

#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags )

创建一个能被user应用程序用于时间等待唤醒机制的 eventfd 对象。
用于内核等待/通知机制通知用户应用程序事件。

initval :
该对象包含一个由内核维护的无符号64位整型(uint64_t)计数器。
此计数器的初始值通过initval指定。一般设0.

flags :
以下标志中按位OR运算以更改eventfd()的行为

EFD_CLOEXEC (since Linux 2.6.27)
Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor.
See the description of the O_CLOEXEC flag in open(2).

EFD_NONBLOCK (since Linux 2.6.27)
Set the O_NONBLOCK file status flag on the new open file description. 
Using this flag saves extra calls to fcntl(2) to achieve the same result.

EFD_SEMAPHORE (since Linux 2.6.30)
Provide semaphore-like semantics for reads from the new file descriptor. 
See below.

read(2) 成功读取返回一个8byte的整数。
read(2) 如果提供的缓冲区的大小小于8个字节,返回错误 EINVAL

write(2)
将缓冲区写入的8字节整形值加到内核计数器上。
计数器中,可以写入的最大值是最大的无符号64位值减1(即0xfffffffffffffffe)。

返回值:

On success, eventfd() returns a new eventfd file descriptor. 
On error, -1 is returned and errno is set to indicate the error.

示例

#include <iostream>
#include <assert.h>
#include <poll.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <string.h>
#include <thread>

static int s_efd = 0;

int createEventfd() {
  int evtfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);

  std::cout << "createEventfd() fd : " << evtfd << std::endl;

  if (evtfd < 0) {
    std::cout << "Failed in eventfd\n";
    assert(evtfd >= 0);
  }

  return evtfd;
}

void testThread() {
  int timeout = 0;
  while(timeout < 3) {
    sleep(1);
    timeout++;
  }

  uint64_t one = 1;
  ssize_t n = write(s_efd, &one, sizeof one);
  if(n != sizeof one) {
    std::cout << " writes " << n << " bytes instead of 8\n";
  }
}

int main()
{
  s_efd = createEventfd();

  fd_set rdset;
  FD_ZERO(&rdset);
  FD_SET(s_efd, &rdset);

  struct timeval timeout;
  timeout.tv_sec = 1;
  timeout.tv_usec = 0;

  std::thread t(testThread);

  while(1) {
    if(select(s_efd + 1, &rdset, NULL, NULL, &timeout) == 0) {
      std::cout << "timeout\n";
      timeout.tv_sec = 1;
      timeout.tv_usec = 0;
      FD_SET(s_efd, &rdset);
        continue;
    }

    uint64_t one = 0;

    ssize_t n = read(s_efd, &one, sizeof one);
    if(n != sizeof one) {
      std::cout << " read " << n << " bytes instead of 8\n";
    }

    std::cout << " wakeup !\n";
    break;
  }

  t.join();
  close(s_efd);

  return 0;
}
./test.out
createEventfd() fd : 3
timeout
timeout
timeout
wakeup!

eventfd 单纯使用文件描述符实现线程间的通知机制,
可以很好的融入select、poll、epoll的I/O复用机制中.

Guess you like

Origin blog.csdn.net/wangkai6666/article/details/119484104