Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl-fork()后面的初始化与单元化词法变量_Perl_Variables_Fork - Fatal编程技术网

Perl-fork()后面的初始化与单元化词法变量

Perl-fork()后面的初始化与单元化词法变量,perl,variables,fork,Perl,Variables,Fork,我使用Lincoln Stein的优秀网络编程与Perl书籍中的一些习惯用法来编写服务器。对于一个在fork之前声明并在fork之后引用的变量,我似乎发现了一些奇怪的行为 这里有一个完整的程序来说明这个问题。(我很抱歉没有被进一步删减;当我删掉所有我认为不相关的东西时,问题就消失了。)如果你寻找。\35;神秘的你会看到两个版本的声明我的$pid。一个版本有效,而另一个版本无效。调用been_daemon()(它将子PID分配给$PID)之后,我尝试将其写入PID文件,然后验证这是否有效。根据我使

我使用Lincoln Stein的优秀网络编程与Perl书籍中的一些习惯用法来编写服务器。对于一个在fork之前声明并在fork之后引用的变量,我似乎发现了一些奇怪的行为

这里有一个完整的程序来说明这个问题。(我很抱歉没有被进一步删减;当我删掉所有我认为不相关的东西时,问题就消失了。)如果你寻找
。\35;神秘的
你会看到两个版本的声明
我的$pid
。一个版本有效,而另一个版本无效。调用
been_daemon()
(它将子PID分配给$PID)之后,我尝试将其写入PID文件,然后验证这是否有效。根据我使用的声明方法,它要么成功,要么失败。我不明白

#!/usr/bin/perl 
#
# Prototype contactd master server

use warnings;
use strict;
use Carp;
use Getopt::Std;
use File::Basename;
use IO::Socket;
use IO::File;
use Net::hostent;    # for OO version of gethostbyaddr
use POSIX qw{WNOHANG setsid};
use Data::Dumper;

#use 5.010;
sub say { print "@_\n"; }

my $program        = basename $0;
my $default_config = "$program.config";

$| = 1;              # flush STDOUT buffer regularly

my %opts;

my $config_file = $opts{c} || $default_config;

# Process the config file to obtain default settings
#
# Note: for now we'll hard code config values into the config hash.
#
my %config;

$config{PORT}      = 2000;
$config{DAEMONIZE} = 0;
$config{VERBOSE}   = 0;
$config{LOGDIR}    = "/mxhome/charrison/private/wdi/logs";
$config{PIDFILE}   = "/var/tmp/$program.pid";

# Process command line args to override default settings
#
my $server_port = $opts{p} || $config{PORT};
my $log_dir     = $opts{l} || $config{LOGDIR};
my $verbose   = !!( exists $opts{v} || $config{VERBOSE} );
my $daemonize = !!( exists $opts{d} || $config{DAEMONIZE} );
my $pid_file = $opts{P} || $config{PIDFILE};

################################################################################
# Set up signal handlers
#
# Caution: these call the logging manager servlog(), which has not yet been
# spawned.
################################################################################

# Set up a child-reaping subroutine for SIGCHLD
#
$SIG{CHLD} = sub {
    local ( $!, $^E, $@ );
    while ( ( my $kid = waitpid( -1, WNOHANG ) ) > 0 ) {
    }
};

# Set up a signal handler for interrupts
#
my $quit = 0;
$SIG{INT} = sub {
    $quit++;
};

# Set up signal handler for pipe errors
#
$SIG{PIPE} = sub {
    local ( $!, $^E, $@ );

};

################################################################################
#                           DAEMONIZATION OCCURS HERE
################################################################################

my $pid_fh = open_pid_file($pid_file);

##### MYSTERY #####

my $pid;           # this makes it work
# my $pid = $$;    # this breaks it!

$daemonize = 1;  # inserted here for demo

if ($daemonize) {
    say "Becoming a daemon and detaching from your terminal.  Bye!";
    $pid = become_daemon();    # update w/new pid
}

say "Here is pid: $pid.  Going to write it to $pid_file and close.";

# If we daemonized, then we are now executing with a different PID
#
# And in that case, the following fails silently!!
#

print $pid_fh $pid;    # store our PID in known location in filesystem
close $pid_fh;

say "Boo boo" if !-e $pid_file;
say qx{cat $pid_file};

##### END OF DEMO #####    

# open_pid_file()
#
# Courtesy of Network Programming with Perl, by Lincoln D. Stein
#
sub open_pid_file {
    my $file = shift;
    if ( -e $file ) {    # PID file already exists
        my $fh = IO::File->new($file) || return;
        my $pid = <$fh>;    # so read it and probe for the process
        croak "Server already running with PID $pid\n"    # die ...
            if kill 0 => $pid;                            # if it responds
        warn "Removing PID file for defunct server process $pid.";
        croak "Can't unlink PID file $file"               # die ...
            unless -w $file && unlink $file;              # if can't unlink
    }
    return IO::File->new( $file, O_WRONLY | O_CREAT | O_EXCL, 0644 )
        or die "Can't create PID file $file: $!\n";
}

# become_daemon()
#
# Courtesy of Network Programming with Perl, by Lincoln D. Stein
#
sub become_daemon {
    die "Can't fork" unless defined( my $child = fork );
    exit 0 if $child != 0;    # die here if parent

    # --- PARENT PROCESS DIES
    # --- CHILD PROCESS STARTS

    setsid();    # Become session leader
    open( STDIN, "</dev/null" );

    # servlog() writes to STDOUT which is being piped to log manager
    #
    #open( STDOUT, ">/dev/null" );
    open( STDERR, ">&STDOUT" );

    chdir '/';    # go to root directory
    umask(0);     # ??
    $ENV{PATH} = '/bin:/sbin:/use/bin:/usr/sbin';
    return $$;
}


END {
    unlink $pid_file if $pid == $$;    # only the daemon unlinks pid file
}
#/usr/bin/perl
#
#原型接触式主服务器
使用警告;
严格使用;
使用鲤鱼;
使用Getopt::Std;
使用File::Basename;
使用IO::Socket;
使用IO::文件;
使用Net::hostent;#对于gethostbyaddr的OO版本
使用POSIXQW{WNOHANG setsid};
使用数据::转储程序;
#使用5.010;
子语句{print“@\n”;}
my$program=basename$0;
my$default_config=“$program.config”;
$| = 1;              # 定期刷新标准缓冲区
我的%opts;
my$config_file=$opts{c}| |$default_config;
#处理配置文件以获取默认设置
#
#注意:现在我们将把配置值硬编码到配置散列中。
#
我的%config;
$config{PORT}=2000;
$config{DAEMONIZE}=0;
$config{VERBOSE}=0;
$config{LOGDIR}=“/mxhome/charrison/private/wdi/logs”;
$config{PIDFILE}=“/var/tmp/$program.pid”;
#处理命令行参数以覆盖默认设置
#
我的$server_port=$opts{p}| |$config{port};
my$log_dir=$opts{l}| |$config{LOGDIR};
我的$verbose=!!(存在$opts{v}| |$config{VERBOSE});
我的$daemonize=!!(存在$opts{d}| |$config{DAEMONIZE});
my$pid_file=$opts{P}| |$config{PIDFILE};
################################################################################
#设置信号处理程序
#
#注意:这些调用了日志管理器servlog(),但它尚未被调用
#产卵。
################################################################################
#为SIGCHLD设置子收获子例程
#
$SIG{CHLD}=sub{
本地($!,$^E,$@);
而((我的$kid=waitpid(-1,WNOHANG))>0){
}
};
#为中断设置信号处理程序
#
我的$quit=0;
$SIG{INT}=sub{
$quit++;
};
#为管道错误设置信号处理程序
#
$SIG{PIPE}=sub{
本地($!,$^E,$@);
};
################################################################################
#DAEMONIZATION发生在这里
################################################################################
my$pid\U fh=打开的pid\U文件($pid\U文件);
#####神秘的#####
我的$pid;#这使它起作用
#我的$pid=$$#这打破了它!
$daemonize=1;#此处插入演示
如果($daemonize){
说“成为一个守护进程并与终端分离。再见!”;
$pid=been_daemon();#使用新pid更新
}
说“这是pid:$pid。将其写入$pid_文件并关闭。”;
#如果我们进行了守护,那么我们现在将使用不同的PID执行
#
#在这种情况下,以下操作会自动失败!!
#
打印$pid_fh$pid;#将PID存储在文件系统中的已知位置
关闭$pid_fh;
说“嘘嘘”如果-e$pid_文件;
说qx{cat$pid_file};
#####演示结束
#打开\u pid\u文件()
#
#由Lincoln D.Stein提供的Perl网络编程
#
子打开\u pid\u文件{
我的$file=shift;
如果(-e$file){PID文件已经存在
my$fh=IO::File->new($File)| return;
我的$pid=##因此请阅读并探索该过程
croak“服务器已在运行,PID$PID\n”#死亡。。。
如果kill 0=>$pid;#如果它响应
警告“正在为失效的服务器进程$PID删除PID文件。”;
哼唱“无法取消PID文件$file的链接”#死亡。。。
除非-w$file&&unlink$file;#如果无法取消链接
}
返回IO::File->new($File,O_WRONLY | O_CREAT | O_EXCL,0644)
或“无法创建PID文件$file:$!\n”;
}
#成为_守护进程()
#
#由Lincoln D.Stein提供的Perl网络编程
#
子进程{
除非定义(my$child=fork),否则die“不能fork”;
如果$child!=0,则退出0;#如果父项为
#---父进程模具
#---子进程开始
setsid();#成为会话负责人
打开(标准输入,“/dev/null”);
打开(标准字符“>”和标准字符“);
chdir“/”#转到根目录
乌马斯克(0);#??
$ENV{PATH}='/bin:/sbin:/use/bin:/usr/sbin';
返回$$;
}
结束{
如果$pid=$$;#只有守护进程取消链接pid文件,则取消链接$pid#文件
}

在代码末尾,您有:

END {
    unlink $pid_file if $pid == $$;    # only the daemon unlinks pid file
}
如果父进程中未定义
$pid
,则此操作正常。但是,如果您将其初始化为父进程的ID,那么只要
成为\u daemon
调用
退出
,父进程就会取消PID文件的链接

(在我看来,在编写PID文件的子级和取消链接的父级之间存在竞争,因此结果可能并不总是相同的。)


编辑:实际上,没有竞争,因为PID文件是在fork之前打开的。因此,父进程打开文件,分叉子进程,取消文件链接并退出。子进程仍然对文件和它有一个句柄,但该文件不再从文件系统中的任何位置链接,它将在子进程退出后立即消失。

在代码末尾,您有:

END {
    unlink $pid_file if $pid == $$;    # only the daemon unlinks pid file
}
如果父进程中未定义
$pid
,则此操作正常。但是,如果您将其初始化为父进程的ID,那么只要
成为\u daemon
调用
退出
,父进程就会取消PID文件的链接