Linux::Inotify2 和线程

Posted

技术标签:

【中文标题】Linux::Inotify2 和线程【英文标题】:Linux::Inotify2 and threads 【发布时间】:2018-02-02 19:44:24 【问题描述】:

我尝试使用 Linxu::Inotify2 - 但不是在线程中。

如果我在程序中有线程,那么我会在读取 Inotify 时崩溃。 如果我不使用线程,一切都很好。

这里有一个小样本应该可以显示问题。

use strict;
use warnings;
use threads;
use Linux::Inotify2;

my $X = 0;  # terminate the thread: 0=nothing, 1=detach, 2=join

STDOUT->autoflush ();
my $ino = new Linux::Inotify2 ();

$ino->blocking (0);
$ino->watch (".", IN_MODIFY | IN_ATTRIB | IN_CREATE) or die "error";

my @ls = ();   # for save threads if $X == 2
for (my $i=0;;$i++)

    my $th = threads->create (sub  print "\nTH". shift; , $i);  # just to have threads; do nothing
    if ($X == 1)
    
        $th->detach ();     # detach the thread
    
    elsif ($X == 2)
    
        push (@ls, $th);    # save for joining after thread finished
    

    my @events = $ino->read ();   # *** CRASH if $X = 1 or 2
    if ($X == 2)
    
        foreach (@ls)
        
            if ($_->is_joinable ())
            
                $_->join ();
            
        
    

    sleep (1);

如果我将 $X 设置为 0,它将起作用。 如果我将其设置为 1 或 2,则会出现运行时错误。

Linux::Inotify2: read error while reading events at /usr/local/lib/x86_64-linux-gnu/perl/5.26.0/Linux/Inotify2.pm line 266.

为什么会这样?

编辑

我简化了我的示例,以便更好地了解问题。

use strict;
use warnings;
use threads;
use Linux::Inotify2;

STDOUT->autoflush ();
my $ino = new Linux::Inotify2 ();

$ino->blocking (0);
$ino->watch (".", IN_CREATE | IN_DELETE) or die "error";

my $th = threads->create (sub   );
$th->join ();

print "\nINO: ".$ino->poll();

删除加入就可以了,保留它,投票会失败。

【问题讨论】:

(1) inotify 需要一个事件循环。您还需要手动poll,因为您将其设置为非阻塞。 “它会起作用”是什么意思——它不会“崩溃”? (2) 那是一个无限循环吗?它多久会与线程崩溃? (3)“崩溃”是什么意思——段错误?如果没有,您是否尝试将其包装在 eval 中并查看错误?我暂时无法尝试。 /// 顺便说一句,分离线程真的没有任何目的。 我隐约记得一个条目不能有多个手表? (现在在文档中找不到它。)每个添加的线程都会选择$ino,因此它们会违反该限制(如果为真)。 使用 read 或 poll 没有区别。 【参考方案1】:

下面的例子实现了 zdim 的想法,他提出使用带有 poll() 而不是 read() 的事件循环。它是在 CentOS 7 上使用 Perl 5.16.2 和 Linux-Inotify2 v1.22 开发的。

程序生成一个线程来监视/tmp 目录。您可以通过触摸和删除文件来测试它:touch /tmp/1 /tmp/2 && rm /tmp/1 /tmp/2

#!/usr/bin/env perl

use warnings FATAL => 'all';
use strict;
use threads;

threads->new(\&_eventListener, '/tmp')->join();

sub _eventListener 
  my ($path) = @_;

  require Linux::Inotify2;
  Linux::Inotify2->import(qw(IN_CREATE IN_DELETE IN_DELETE_SELF));

  my $fsEventListener = Linux::Inotify2->new() or 
    die('Cannot register Linux::Inotify2, stopped');

  $fsEventListener->watch(
    $path, 
    IN_CREATE() | IN_DELETE() | IN_DELETE_SELF(), 
    \&_watchCallback
  ) or die("Watch creation failed. '$!'");

  $fsEventListener->blocking(undef);

  while(1) 
    $fsEventListener->poll();
    sleep 1;
  

  return;


sub _watchCallback 
  my ($e) = @_;

  printf STDOUT "Receive event '0x%04x' for file '%s'\n", $e->mask(), $e->fullname();

  return;

【讨论】:

以上是关于Linux::Inotify2 和线程的主要内容,如果未能解决你的问题,请参考以下文章

Perl Linux::Inotify2 - 不能再响应事件了

为啥inotify会丢失事件?

在 perl 中使用 inotify 监视多个文件

在后台运行的单个 perl 脚本可以保存多个 Log4Perl 实例吗?

异步读取 inotify 描述符失败

inotify实时无差异同步