目录
1.eventfd
1.1.核心接口
[2.struct stat](#2.struct stat)
[2.1 核心字段说明](#2.1 核心字段说明)
[2.2 st_mode 详解](#2.2 st_mode 详解)
文件类型判断宏
权限判断宏
[2.3 stat 、lstat、fstat函数](#2.3 stat 、lstat、fstat函数)
三者对比
1.eventfd
- eventfd 是 Linux 提供的一种轻量级事件通知机制,本质上是一个内核维护的 64 位无符号整数计数器,通过文件描述符来操作
- 它的核心用途是在线程间或进程间实现信号传递,典型场景是 epoll 事件驱动架构。相比于管道(pipe),它更轻量,无需管理缓冲区,开销更低
1.1.核心接口
| 项目 |
详细说明 |
| 函数原型 |
int eventfd(unsigned int initval, int flags); |
| 所属头文件 |
<sys/eventfd.h> |
| 作用 |
创建一个 eventfd 对象,返回一个指向它的文件描述符 |
参数 initval |
计数器的初始值(uint64_t 类型,范围 0 ~ 0xfffffffffffffffe) |
参数 flags |
行为控制标志,按位或组合(详见下方 flags 表) |
| 成功返回值 |
新的文件描述符(非负整数) |
| 失败返回值 |
-1,并设置 errno |
可能 errno |
EINVAL:flags 无效 EMFILE:进程 fd 数达上限 ENFILE:系统 fd 数达上限 ENOMEM:内核内存不足 |
| 标志 |
值 |
作用 |
0 |
0 |
默认模式 :读写均可能阻塞,read() 读后清零 |
EFD_CLOEXEC |
02000000 (八进制) |
exec() 时自动关闭该 fd,防止子进程继承 |
EFD_NONBLOCK |
04000 (八进制) |
非阻塞模式:计数器为 0 时 read() 返回 EAGAIN;即将溢出时 write() 返回 EAGAIN |
EFD_SEMAPHORE |
1 |
信号量模式:read() 每次减 1 并返回 1,支持多消费者场景 |
| 组合 |
场景 |
eventfd(0, 0) |
线程间同步,阻塞等待事件 |
eventfd(0, EFD_NONBLOCK) |
在轮询循环中使用,不阻塞线程 |
| `eventfd(0, EFD_CLOEXEC |
EFD_NONBLOCK)` |
| `eventfd(0, EFD_SEMAPHORE |
EFD_NONBLOCK)` |
| 项目 |
详细说明 |
| 函数原型 |
ssize_t write(int fd, const void *buf, size_t count); |
| 所属头文件 |
<unistd.h> |
| 对 eventfd 的作用 |
将 buf 中的 8 字节无符号整数值加到内核计数器上 |
参数 fd |
eventfd 的文件描述符 |
参数 buf |
指向一个 uint64_t 值的指针**(必须是 8 字节)** |
参数 count |
写入字节数,必须为 8 |
| 写入规则 |
1. 写入值被加到计数器 2. 如果结果超过 0xfffffffffffffffe,调用阻塞(除非设了 EFD_NONBLOCK) 3. 写入值为 0 是合法的,但不改变计数器,用于唤醒阻塞的 read() |
| 成功返回值 |
8(永远完整写入,不存在部分写入) |
| 失败返回值 |
-1,并设置 errno |
可能 errno |
EAGAIN:非阻塞模式下,写入会导致计数器溢出 EINVAL:count 不等于 8 或 buf 值非法 EBADF:fd 无效 EINTR:被信号中断 |
| 项目 |
详细说明 |
| 函数原型 |
ssize_t read(int fd, void *buf, size_t count); |
| 所属头文件 |
<unistd.h> |
| 对 eventfd 的作用 |
读取计数器的值,并根据模式清零或减 1 |
参数 fd |
eventfd 的文件描述符 |
参数 buf |
指向一个 uint64_t 变量的缓冲区(至少 8 字节) |
参数 count |
缓冲区大小,必须 ≥ 8 |
| 默认模式读取规则 |
1. 计数器 > 0:返回当前计数,原子清零 2. 计数器 = 0:阻塞,直到有 write() 写入值 3. 非阻塞:返回 EAGAIN |
EFD_SEMAPHORE 模式 |
1. 计数器 > 0:返回固定值 1,原子减 1 2. 计数器 = 0:阻塞(非阻塞返回 EAGAIN) 3. 相当于每次消耗一个"事件资源" |
| 成功返回值 |
8(读取到的 8 字节值填入 buf) |
| 失败返回值 |
-1,并设置 errno |
可能 errno |
EAGAIN:非阻塞模式下计数器为零 EINVAL:count < 8 EBADF:fd 无效 EINTR:被信号中断 |
| 项目 |
详细说明 |
| 函数原型 |
int close(int fd); |
| 所属头文件 |
<unistd.h> |
| 作用 |
释放 eventfd 对象及其内核资源 |
参数 fd |
eventfd 的文件描述符 |
| 成功返回值 |
0 |
| 失败返回值 |
-1,并设置 errno |
可能 errno |
EBADF:fd 无效 |
| 注意事项 |
如果多个进程/线程共享同一个 fd(如通过 fork 或 fd 传递),只有在所有引用该对象的 fd 都关闭后,内核计数器才真正释放 |
2.struct stat
struct stat 是 POSIX 标准中用于存储文件元信息的结构体,定义在 <sys/stat.h>
复制代码
struct stat {
dev_t st_dev; // 文件所在设备的 ID
ino_t st_ino; // inode 节点号
mode_t st_mode; // 文件类型和权限
nlink_t st_nlink; // 硬链接数
uid_t st_uid; // 所有者用户 ID
gid_t st_gid; // 所属组 ID
dev_t st_rdev; // 设备文件对应的设备 ID(非设备文件无意义)
off_t st_size; // 文件大小(字节),普通文件才有意义
blksize_t st_blksize; // 文件系统 I/O 最优块大小
blkcnt_t st_blocks; // 文件占用的 512B 块数量
time_t st_atime; // 最后访问时间(access)
time_t st_mtime; // 最后修改时间(modify)
time_t st_ctime; // 最后状态改变时间(change)
};
2.1 核心字段说明
| 字段 |
类型 |
含义 |
使用场景 |
st_mode |
mode_t |
文件类型 + 权限 |
最常用,判断文件类型和权限 |
st_size |
off_t |
文件大小 |
获取文件大小,分配缓冲区 |
st_mtime |
time_t |
最后修改时间 |
HTTP 的 Last-Modified 头、缓存判断 |
st_ino |
ino_t |
inode 号 |
判断两个路径是否指向同一文件 |
st_nlink |
nlink_t |
硬链接数 |
判断文件是否有其他名字(为 0 时文件真正删除) |
st_uid/st_gid |
uid_t/gid_t |
所有者/组 |
权限检查 |
2.2 st_mode 详解
st_mode 是一个位掩码,包含两部分信息:文件类型(高 4 位)访问权限(低 12 位)
文件类型判断宏
| 宏 |
含义 |
示例 |
S_ISREG(m) |
普通文件 |
.txt, .html, 可执行文件 |
S_ISDIR(m) |
目录 |
/home, /tmp |
S_ISLNK(m) |
符号链接 |
软链接文件 |
S_ISCHR(m) |
字符设备 |
/dev/tty, /dev/null |
S_ISBLK(m) |
块设备 |
/dev/sda, /dev/sdb |
S_ISFIFO(m) |
命名管道 |
FIFO 文件 |
S_ISSOCK(m) |
套接字 |
socket 文件 |
权限判断宏
st.st_mode & S_XXX
| 宏 |
含义 |
八进制值 |
S_IRUSR |
所有者读 |
0400 |
S_IWUSR |
所有者写 |
0200 |
S_IXUSR |
所有者执行 |
0100 |
S_IRGRP |
组读 |
0040 |
S_IWGRP |
组写 |
0020 |
S_IXGRP |
组执行 |
0010 |
S_IROTH |
其他人读 |
0004 |
S_IWOTH |
其他人写 |
0002 |
S_IXOTH |
其他人执行 |
0001 |
2.3 stat 、lstat、fstat函数
复制代码
#include <sys/stat.h>
int stat(const char *pathname, struct stat *statbuf);
| 参数 |
类型 |
方向 |
说明 |
pathname |
const char * |
输入 |
文件路径(绝对或相对,支持符号链接跟随) |
statbuf |
struct stat * |
输出 |
用于存储文件元信息的结构体指针 |
| 返回值 |
含义 |
后续操作 |
0 |
成功,statbuf 已填充 |
读取 statbuf 中各字段 |
-1 |
失败 |
检查 errno 获取原因 |
2 |
ENOENT |
文件不存在 |
13 |
EACCES |
路径中某个目录无搜索权限 |
20 |
ENOTDIR |
路径中某个组件不是目录 |
36 |
ENAMETOOLONG |
路径名太长 |
40 |
ELOOP |
符号链接循环引用 |
14 |
EFAULT |
pathname 或 statbuf 指针无效 |
12 |
ENOMEM |
内核内存不足 |
116 |
ESTALE |
NFS 文件句柄过期 |
复制代码
#include <sys/stat.h>
int lstat(const char *pathname, struct stat *statbuf);
| 项目 |
说明 |
| 参数 |
同 stat:pathname(输入路径)、statbuf(输出信息) |
| 返回值 |
同 stat:成功返回 0,失败返回 -1 并设置 errno |
| errno |
同 stat:ENOENT、EACCES、ENOTDIR、ELOOP 等 |
| 核心区别 |
若 pathname 是符号链接,返回符号链接自身的信息,而非目标文件 |
复制代码
#include <sys/stat.h>
int fstat(int fd, struct stat *statbuf);
| 项目 |
说明 |
| 参数 |
fd:已打开的文件描述符(输入);statbuf:输出信息 |
| 返回值 |
成功返回 0,失败返回 -1 并设置 errno |
| errno |
EBADF(9):fd 无效;EFAULT(14):statbuf 指针无效;ENOMEM(12):内存不足 |
| 核心区别 |
通过文件描述符获取信息,无需文件名,适用于已打开的文件 |
三者对比
|----------|----------------|----------------|----------------|
| | stat | lstat | fstat |
| 输入 | 路径字符串 | 路径字符串 | 文件描述符 |
| 符号链接 | 跟随,返回目标信息 | 不跟随,返回链接自身 | 跟随(文件已打开) |
| 典型场景 | 查询任意文件信息 | 判断文件是否为符号链接 | 已 open() 后查询 |
| 头文件 | <sys/stat.h> | <sys/stat.h> | <sys/stat.h> |