eventfd()创建了一个“eventfd对象”, 通过它能够实现用户态程序间。
此对象包含了一个被内核所维护的计数(uint64_t), 初始值由initval来决定。
eventfd在内核里的核心是一个计数器counter,它是一个uint64_t的整形变量counter,初始值为initval。
1.read(eventfd_read)
消费者需要对信号量进行down操作时,调用read从eventfd读即可。read返回值:
如果当前counter > 0,那么read返回counter值,并重置counter为0;
如果当前counter等于0,那么read 1)阻塞直到counter大于0;2)如果设置了NONBLOCK,那么返回-1,并设置errno为EAGAIN。
可以看到,eventfd实现的资源是一次性消耗品,只允许一次read。
2.write(eventfd_write)
生产者需要执行up操作时,调用write写一个64bit的整数value到eventfd即可。write返回值:
counter最大能存储的值是 0xffff ffff ffff fffe(以max表示此值),那么write尝试将value加到counter上,如果结果超过max,那么write一直阻塞直到有read操作发生,或者返回-1并设置errno为EAGAIN。
所以write可以多次连续调用,但read读一次即可清零。实质上它应该是一个二元信号量,只有0和非0两种状态。
*int eventfd(unsigned int initval, int flags);创建一个eventfd文件描述符
int eventfd_read(int fd, eventfd_t value); 向eventfd中写入一个值
int eventfd_write(int fd, eventfd_t value); 从eventfd中读出一个值
1、子线程多次写入多个值,主线程一次读出所有值的和
#include <sys/eventfd.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int main(int argc, char**argv[])
{
int efd, j;
uint64_t u;
ssize_t s;
if (argc < 2)
{
printf("number of argc is wrong!\n");
return 0;
}
efd = eventfd(0,0);
if (-1 == efd)
{
printf("failed to create eventfd\n");
}
switch(fork())
{
case 0:
{
for(j=1; j<argc;j++)
{
printf("child writing %s to efd\n", argv[j]);
u = strtoull(argv[j], NULL, 0);
s = write(efd, &u, sizeof(uint64_t));
if (s!=sizeof(uint64_t))
{
printf("write efd failed\n");
}
}
printf("Child completed write loop\n");
exit(0);
}
default:
sleep(2);
printf("Parents about to read\n");
s = read(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
{
printf("read efd failed\n");
}
printf("Parents first read %llu (0x%llx) from efd\n", u, u);
exit(0);
case -1:
{
printf("fork error\n");
}
}
return 0;
}
二、eventfd可以被epoll监控, 一旦有状态变化,可以触发通知
#include <sys/eventfd.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/epoll.h>
#include <string.h>
#include <pthread.h>
int g_iEvtfd = -1;
void *eventfd_child_Task(void *pArg)
{
uint64_t uiWrite = 1;
while(1)
{
sleep(2);
if (0 != eventfd_write(g_iEvtfd, uiWrite))
{
printf("child write iEvtfd failed\n");
}
}
return;
}
int main(int argc, char**argv[])
{
int iEvtfd, j;
uint64_t uiWrite = 1;
uint64_t uiRead;
ssize_t s;
int iEpfd;
struct epoll_event stEvent;
int iRet = 0;
struct epoll_event stEpEvent;
pthread_t stWthread;
iEpfd = epoll_create(1);
if (-1 == iEpfd)
{
printf("Create epoll failed.\n");
return 0;
}
iEvtfd = eventfd(0,0);
if (-1 == iEvtfd)
{
printf("failed to create eventfd\n");
return 0;
}
g_iEvtfd = iEvtfd;
memset(&stEvent, 0, sizeof(struct epoll_event));
stEvent.events = (unsigned long) EPOLLIN;
stEvent.data.fd = iEvtfd;
iRet = epoll_ctl(iEpfd, EPOLL_CTL_ADD, g_iEvtfd, &stEvent);
if (0 != iRet)
{
printf("failed to add iEvtfd to epoll\n");
close(g_iEvtfd);
close(iEpfd);
return 0;
}
iRet = pthread_create(&stWthread, NULL, eventfd_child_Task, NULL);
if (0 != iRet)
{
close(g_iEvtfd);
close(iEpfd);
return;
}
for(;;)
{
iRet = epoll_wait(iEpfd, &stEpEvent, 1, -1);
if (iRet > 0)
{
s = eventfd_read(iEvtfd, &uiRead);
if (s != 0)
{
printf("read iEvtfd failed\n");
break;
}
printf("Read %llu (0x%llx) from iEvtfd\n", uiRead, uiRead);
}
}
close(g_iEvtfd);
close(iEpfd);
return 0;
}
来源:CSDN
作者:风@@痕
链接:https://blog.csdn.net/weixin_42262854/article/details/103538800