繁体   English   中英

inotify 是一次性解决方案吗

[英]Is inotify a one shot only solution

我有一个使用 inotify 的程序。

它的作用是开始监视正在创建的文件的目录。 当它发生时,程序读取内容然后删除文件。

然后用户启动将再次创建相同文件的操作。 但是,inotify 没有看到该文件已被第二次创建并且该文件未被处理。

代码如下:

fileCreated = false;
m_wd1 = inotify_add_watch( m_fd, "/tmp", IN_CREATE );
if( m_wd1 == -1 )
{
}
else
{
    while( true )
    {
        poll_num = poll( &fds, nfds, -1 );
        if( poll_num == -1 )
        {
            if( errno == EINTR )
                continue;
            syslog( LOG_ERR, "Fail to run poll" );
            result = 1;
        }
        else if( poll_num > 0 && ( fds.revents & POLLIN ) )
        {
            syslog( LOG_DEBUG, "Polling is successful" );
            for( ;; )
            {
                len = read( m_fd, buf, sizeof( buf ) );
                if( len == -1 && errno != EAGAIN )
                {
                    syslog( LOG_ERR, "Failure to read the inotify event" );
                    result = 1;
                    break;
                }
                for( ptr = buf; ptr < buf + len; ptr += sizeof( struct inotify_event ) + event->len )
                {
                    event = (const struct inotify_event *) ptr;
                    if( event->mask & IN_CREATE )
                    {
                        std::string name( event->name );
                        if( name == "scan_results" )
                        {
                            fileCreated = true;
                            break;
                        }
                    }
                }
                if( fileCreated || result )
                    break;
            }
        }
        if( fileCreated )
        {
            std::ifstream log( "scan_results" );
            if( log.rdstate()  & std::ifstream::failbit ) != 0 )
            {
            }
            else
            {
            }
            log.close();
            if( remove( "scan_results" ) != 0 )
            {
                syslog( LOG_ERR, "Failed to remove the file" );
            }
            else
            {
                syslog( LOG_DEBUG, "File deleted successfully" );
            }
        }
        fileCreated = false;

while() 循环只运行一次。 当该操作第二次发生时,我看到一条消息“轮询成功”。

我应该添加 IN_MODIFY 作为 inotify 的掩码吗?

如果重要的话 - 此代码在 std::thread 中运行。

事实证明,轮询加读取 inotify 不是线程安全的。

所以为了克服这个问题,我必须在每个线程中添加inotify_init() 所以现在每个线程都有自己的 inotify 文件描述符。 现在看起来程序可以工作了。

感谢大家阅读并提供帮助。

好吧,我有一个答案,它不是一个简短的答案,它直接来自上面评论中链接的man 7 inotify页面。 您在评论中缩小问题的两个未决问题是:

  1. 如果我在文件上调用remove() - 这是否意味着目录中用于创建文件的监视将被删除?
  2. 如果是真的,你能给我一些解决方法的伪代码吗?

(1)的答案是Yes ,但是手表可能会被回收,从而导致分配给它的下一个文件/目录可能读取已关闭/删除的文件/目录的挂起请求:

 When a watch descriptor is removed by calling inotify_rm_watch(2) (or because a watch file is deleted or the filesystem that contains it is unmounted), ...

(需要注意的警告)

 ... any pending unread events for that watch descriptor remain available to read. As watch descriptors are subsequently allocated with inotify_add_watch(2), the kernel cycles through the range of possible watch descriptors (0 to INT_MAX) incrementally. When allocating a free watch descriptor, no check is made to see whether that watch descriptor number has any pending unread events in the inotify queue. Thus, it can happen that a watch descriptor is reallocated even when pending unread events exist for a previous incarnation of that watch descriptor number, with the result that the application might then read those events and interpret them as belonging to the file associated with the newly recycled watch descriptor. In practice, the likelihood of hitting this bug may be extremely low, since it requires that an application cycle through INT_MAX watch descriptors, release a watch descriptor while leaving unread events for that watch descriptor in the queue, and then recycle that watch descriptor. For this reason, and because there have been no reports of the bug occurring in real-world applications, as of Linux 3.15, no kernel changes have yet been made to eliminate this possible bug.

(我怀疑你会打开那么多手表)

在回答第二个问题时,伪代码只是检查掩码

 IN_DELETE_SELF Watched file/directory was itself deleted. (This event also occurs if an object is moved to another filesystem, since mv(1) in effect copies the file to the other filesystem and then deletes it from the original filesys‐ tem.) In addition, an IN_IGNORED event will subsequently be generated for the watch descriptor.

因此,如果正在监视的文件/目录被删除,您可以使用掩码IN_DELETE_SELFIN_IGNORED检查。

由于您没有提供mcve ,因此我无法确切地看到您的代码有什么问题,但是观看目录应该会为您提供该目录的所有订阅事件,直到您停止阅读它们。

这是使用inotify监视目录的示例...

#include <iostream>

#include <unistd.h>
#include <sys/inotify.h>

int main(int argc, char *argv[]) {

  const int ifd = inotify_init();
  const int iwd = inotify_add_watch(ifd, "/tmp/inotify", IN_CREATE);

  char buf[4096];

  while (read(ifd, buf, sizeof(buf)) > 0) {

    const struct inotify_event* ie = (const struct inotify_event*) buf;

    std::cout << ie->name << std::endl;
  }

  return 0;
}

(jason@pi) [4868] ~/tmp touch /tmp/inotify/foo
(jason@pi) [4880] ~/tmp touch /tmp/inotify/bar
(jason@pi) [4881] ~/tmp rm /tmp/inotify/foo
(jason@pi) [4882] ~/tmp touch /tmp/inotify/foo

(jason@pi) [4879] ~/tmp ./so
foo
bar
foo

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM