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 | // 只需导入单个头文件 |