【问题标题】:inotify notifies of a new file wrongly multiple timesinotify 多次错误地通知新文件
【发布时间】:2012-08-27 18:05:33
【问题描述】:

使用 inotify 通过在目录上添加监视来监视目录中创建的任何新文件

    fd = inotify_init();
    wd = inotify_add_watch(fd, "filename_with_path", IN_CLOSE_WRITE);
    inotify_add_watch(fd, directory_name, IN_CLOSE_WRITE);

    const int event_size = sizeof(struct inotify_event);
    const int buf_len = 1024 * (event_size + FILENAME_MAX);
    while(true) {
        char buf[buf_len];
        int no_of_events, count = 0;
        no_of_events = read(fd, buf, buf_len);
        while(count < no_of_events) {
            struct inotify_event *event = (struct inotify_event *) &buf[count];
            if (event->len) {
                if (event->mask & IN_CLOSE_WRITE) {
                    if (!(event->mask & IN_ISDIR)) {
                         //It's here multiple times 
                    }
                }
            }
            count += event_size + event->len;
        }

当我将文件 scp 到目录时,它会无限循环。这段代码有什么问题?它也显示相同的事件名称和事件掩码。因此,它表明该事件发生了相同的无限次。

没有中断语句。如果我找到一个事件,我只需打印它并继续等待 read() 上的另一个事件,这应该是一个阻塞调用。相反,它开始无限循环。这意味着, read 不会阻塞它,而是无限地为一个文件返回相同的值。

整个操作在单独的 boost::thread 上运行。

编辑: 对不起大家。我得到的错误不是因为 inotify 而是因为 sqlite 一开始很难检测到。我想我在这里开枪了。经过进一步调查,我确实发现 inotify 运行良好。但错误实际上来自 sqlite 命令:ATTACH

该命令并非应有的现成命令。它正在将一些元数据写入文件。因此 inotify 一次又一次地收到通知。由于它们发生得如此之快,它搞砸了应用程序。我最终不得不分解代码以了解原因。

谢谢大家。

【问题讨论】:

  • 我看不出这段代码有什么问题。也许您没有包含在 if 块中的代码使用了一个跳过 count 变量增量的 break 语句?
  • 没有中断语句。如果我找到一个事件,我只是打印它并继续等待 read() 上的另一个事件,这应该是一个阻塞调用。
  • 在增量后打印count的值。它会打印预期的内容吗?
  • 发生这种情况时在您的程序上运行strace,它可能会提供更多信息
  • count 增加得很好。只有 [read] 永远一次又一次地赋予我相同的价值。

标签: c++ c linux boost-thread inotify


【解决方案1】:

我没有发现您的代码有任何问题...我运行的基本相同,并且运行良好。我想知道测试是否有问题,或者代码的某些部分被省略了。如果您不介意,让我们看看我们是否可以消除任何歧义。

你能试试这个(我知道这几乎是一样的,但只是幽默我)并告诉我确切的测试结果吗?

1) 将以下代码放入test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/inotify.h>

int main (int argc, char *argv[])
{
   char target[FILENAME_MAX];
   int result;
   int fd;
   int wd;   /* watch descriptor */
   const int event_size = sizeof(struct inotify_event);
   const int buf_len = 1024 * (event_size + FILENAME_MAX);

   strcpy (target, ".");

   fd = inotify_init();
   if (fd < 0) {
      printf ("Error: %s\n", strerror(errno));
      return 1;
   }

   wd = inotify_add_watch (fd, target, IN_CLOSE_WRITE);
   if (wd < 0) {
      printf ("Error: %s\n", strerror(errno));
      return 1;
   }

   while (1) {
     char buff[buf_len];
     int no_of_events, count = 0;

     no_of_events = read (fd, buff, buf_len);

     while (count < no_of_events) {
       struct inotify_event *event = (struct inotify_event *)&buff[count];

       if (event->len){
         if (event->mask & IN_CLOSE_WRITE)
           if(!(event->mask & IN_ISDIR)){
              printf("%s opened for writing was closed\n", target);
              fflush(stdout);
           }
       }
       count += event_size + event->len;
     }
   }

   return 0;
}

2) 用 gcc 编译:

gcc test.c

3) 在一个窗口中启动它:

./a.out

4) 在同一目录的第二个窗口中试试这个:

echo "hi" > blah.txt

让我知道每次写入文件时是否可以正常显示输出并且不会像您的代码那样循环。如果是这样,那么您在代码中省略了一些重要的东西。如果不是,那么系统会有所不同。

很抱歉将其放在“答案”部分,但评论太多了。

【讨论】:

  • 整个操作在一个单独的 boost::thread 上的 c++ 应用程序中运行。我的代码和你的完全一样。但就你的努力而言,我想在 c 中运行它。发现该部件运行正常。但是单独运行也应该运行良好。现在我确定 inotify 没有完全破坏,但我因为某些事情被欺骗了。我将深入研究并返回详细信息。谢谢。
  • 很高兴知道这不是完全浪费时间。由于我们已经确定底层 inotify 功能正在运行,如果您可以向我们提供运行此代码的 C++ 应用程序的更多详细信息,或许我们可以帮助缩小导致失败的问题范围。
【解决方案2】:

我的猜测是 read 返回 -1 并且由于您从未尝试修复错误,因此您在下一次调用 read 时会收到另一个错误,该错误也返回 -1。

【讨论】:

  • 如果 read 返回 -1,那么它不会走那么远。 count(0)
  • @King 内部循环没有执行,它只是旋转,或者由于强制转换,你得到 MAX_INT 并且它旋转。哦,嘿,感谢 -1 试图提供帮助。非常感谢
  • 内部循环正在执行。它也在 read() 多次之后。它表明同一个事件发生了多次。
  • -1 并不是说​​我不欣赏你。但这不应该是答案,而是评论。我已经添加了一条评论,说我得到了所有东西的正确值。当然,感谢您抽出时间帮助他人。
猜你喜欢
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
相关资源
最近更新 更多