线程间之event

怎甘沉沦 提交于 2019-12-14 17:33:08

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!