Linux基础知识之eventfd

简介

  eventfd顾名思义它就是一个用于事件通知的fd.多用于用户态进程中多线程之间相互通知,也可用于内核事件通知
eventfd

应用场景

  如上图所示,在相同进程中,乙线程无事件可处理时会进行休眠等待.一旦来事件需要处理,甲线程会通过eventfd通知乙线程唤醒并处理事件.

函数原型

SYNOPSIS

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

DESCRIPTION

FLAG 说明
EFD_CLOEXEC 该标志位设置后,当执行exec族函数时,会自动关闭eventfd.防止越权和造成fd leak
EFD_NONBLOCK 该标志位设置后,执行IO操作时不会阻塞,会立即返回.

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

注意:eventfd的read和write函数的形参buf要用uint64_t类型

例子

  这里以C语言为例.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*本例子的流程为: 
* 1.主线程等待终端输入字符串
* 2.readThread线程监听evnetfd,休眠等待事件唤醒
* 3.终端输入字符串,主线程通过写入eventfd唤醒readThread线程
* 4.readThread线程从监听eventfd中唤醒,处理事务(打印终端输入的字符串)
* 5.goto 1
*/
#include <stdio.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define true 1
#define false 0

typedef unsigned char boolean ;

struct Transfer_Data {
int eventFd;
char *msg;
boolean exit;
};
void *thread_func(void *arg) {
struct Transfer_Data *ptd = (struct Transfer_Data *)arg;
uint64_t counter;
int err = 0;
while (ptd -> exit == false) {
printf("wait for event\n");
//读取事件,如果无事件读取,会将线程状态置为TASK_INTERRUPTIBLE进行休眠,等待唤醒
if ((err = read(ptd -> eventFd, &counter, sizeof(uint64_t))) < 0) {
printf("read eventfd fail reason: %s\n",strerror(errno));
ptd -> exit = true;
break;
}
printf("wake up, read the msg : %s\n", ptd -> msg);
}
return NULL;
}

int main(int argc __unused, char **argv __unused) {
int err;
uint64_t inc = 1;
char msg[128] = { 0 }; //作为例子,这里buffer只用了128字节.实际应以需求为准

int mWakeEventFd = eventfd(0, EFD_CLOEXEC); //创建eventfd,设置标志位为EFD_CLOEXEC
if (mWakeEventFd < 0) {
printf("Create eventfd fail reason: %s\n",strerror(errno));
return -1;
}

pthread_t readThread;
struct Transfer_Data td = {mWakeEventFd, msg, false}; //构建要传输的数据:eventfd, msg, exit标志位
err = pthread_create(&readThread, NULL, thread_func, &td); //创建readThread线程
if (err != 0) {
printf("Create thread fail reason: %s\n", strerror(err));
return -1;
}

while (td.exit == false) {
fgets(msg, sizeof(msg) / sizeof(*msg), stdin);
if (write(mWakeEventFd, &inc, sizeof(uint64_t)) < 0) { //写入事件,唤醒readThread线程
printf("write eventfd fail reason: %s\n", strerror(err));
goto EXIT;
}
}
EXIT:
td.exit = true;
pthread_join(readThread, NULL);
close(mWakeEventFd);
return 0;
}

运行结果

1
2
3
4
5
generic_arm64:/ # example
wait for event
Hello World /*<--- 这是终端输入的字符串*/
wake up, read the msg : Hello World
wait for event

本章完