ev_stat
会监视文件系统的相关属性变更. 准确来说, 它会定期调用stat
(或者操作系统通知)查看对比与上次的变化. 只有在文件确实发生了状态变更后才会被报告.
注册ev_stat
指定的路径可以是”不存在”的, 因为从”不存在”变为”存在”也是一种状态. 路径不得以斜杠结尾或包含特殊符号, 如: '.'
和'..'
. 设置的路径最好是绝对路径, 否则工作目录的变更可能导致受到影响.
没有通用的事件接口可以知道这些, 所以最好的办法就是在那些平台定期使用stat
来查询变更. 唯一实现的特定于操作系统的接口是Linux inotify
, kqueue
虽然有一定支持但是无法实现stat
的完整语义.
即使是操作系统支持也不适合启动大量的ev_stat
, 因为这些资源(I/O、CPU)密集型对性能消耗极大.
Libev
使用默认环境时选择的stat
是32
位版本的, 当ABI
改为64
位的时候使用会失败. 这种情况下, 必须使用同样的ABI
版本编译来保障二进制兼容性.
解决这个问题的办法是定制发行版的作者默认使用64
位而并不仅是可选, Libev
不会简单直接的支持, 因为这也需要与编译器、环境进行探测后统计知晓.
当inotify
支持已编译到Libev
并在运行时出现时, 它将尽可能加快更改检测. inotify
描述符将在第一个ev_stat
启动时延迟创建.
inotify
的存在不会改变ev_stat
的语义, 只是能更早的检测到变更信息并且在某些情况下避免stat
调用. 然而, 即使存在inotify
的情况下, 有时候Libev
也必须使用轮询进行统计. 但是只要Linux
内核版本在2.6.25
及以上, Libev
对这些本地文件系统(ext2/3
、ifs
、reisefs
、xfs
)上已存在的路径不需要使用轮询.
不支持kqueue
是因为它显然不能用来实现这个功能, 因为需要在对象上一直打开一个文件描述符, 并且很难检测重命名、断开链接等.
Libev
本身通常不执行任何类型的I/O
, 所以一般不会阻塞住进程. ev_stat
则会是一个例外, 因为它是一个同步操作.
对于本地路径这通常无关紧要: 除非系统非常繁忙或每次stat
之间的间隔很大, 否则stat
调用执行的很快. 因为这时候路劲数据都已经保存在内存中.
但对于远程文件系统, stat()
可能会因为网络问题而长期阻塞. 即使再最好的情况下, 一次stat
也需要毫秒级别的时间间隔.
因此最好避免在NFS
等文件系统上使用ev_stat
, 虽然ev_stat
已经支持这么做.
stat()
系统调用最多支持秒级精度, 即使是在更高精度的系统上大多数情况下也只支持秒级.
这意味着, 如果两次更新的周期很短则容易错过. 即: 同一秒内仅更新了时间, ev_stat
则无法检测到(除非在其它数据层面也发生了变更). 解决问题的办法是将每次操作延迟1.02
秒, 这个0.02
的偏移值是为了解决时间精度不一致的问题.
配置
ev_stat
检查path
的变更,interval
则是每次检查的间隔(通常是0
来让Libev
选择一个合适的值).
当
callback
收到EV_STAT
事件的时候, 表示ev_stat
相对于之前检测到了属性变更.
如果您在上述回调函数中更改了
path
值, 主动调用此函数会立刻更新stat
的更改.
间隔时间.
监视路径.
检测到变更事件之前的文件属性. 每当
prev != attr
的时候, 这些成员中会有一个或多个不同:st_dev
,st_ino
,st_mode
,st_nlink
,st_uid
,st_gid
,st_rdev
,st_size
,st_atime
,st_mtime
,st_ctime
.
最新检测到的变更事件文件属性. 虽然类型是
ev_statdata
, 但是通常是是您系统中的struct stat
类型. 如果st_nlink
为0
, 则说明stat
期间发生了一些错误.
本示例演示了v.log
的文件创建后退出事件循环:
1 | // 只需导入单个头文件 |