1

我是 perl 中多进程编程过程的新手。我正在尝试编写一个基于多线程多进程的应用程序,它给了我“分段故障”。程序很简单。首先,父进程产生几个进程(使用 fork),每个进程在一段时间后运行,并在随机延迟后死亡。同时,父进程产生相同数量的线程来监听每个新分叉的子进程。我正在使用管道在分叉的进程和从主进程产生的线程之间进行通信。这里的想法是,当一个进程死亡时,应该立即使用相同的管道生成另一个新进程,因此在子例程调用之后无限循环。有一段时间,这可以正常工作,但突然出现分段错误。我该如何调试这样的场景?我的 PERL 版本是 5.8.8

#!/usr/local/bin/perl -w
use strict;
use threads;
use threads::shared;
use IO::Pipe;
use warnings;
print "Starting main program\n";
my $ACTIVE_PROCESSES :shared =0;
my $MAX_PROCESSES:shared =5,
my %process_state_list : shared;
my %process_id_list : shared;
$SIG{CHLD} = sub { wait };
my $GLOBAL_COUNT=0;
my @pipe_array=&share([]);
&init_pipes();
&spawn_process();
while(1)
{
for (my $i=0;$i<$MAX_PROCESSES;$i++)
 {
    if ($process_state_list{$i} =~ /INACTIVE/)
    {
        print "Found Process $i is inactive\n"; 
    spawn_next_process($i);
    }
 }
}
print "End of main program from $$\n";

sub init_pipes
{
my $i=0;
for ($i=0;$i< $MAX_PROCESSES; $i++)
  { 
    $pipe_array[$i] = IO::Pipe->new();
    $process_state_list{$i}="INACTIVE";
    print "Pipe $i initialized to $pipe_array[$i]\n";
  }
}
sub spawn_process
{
print "Spawn process called..\n";
while ( $ACTIVE_PROCESSES < $MAX_PROCESSES) 
   {
      $GLOBAL_COUNT++;
      PARENT_create_child();
      PARENT_create_child_listener();
   }
}

sub PARENT_update_child_map
{
my ($i,$cmd)=@_;
if ($cmd =~ /CREATE/)
  {
    for (my $j=0;$j<$MAX_PROCESSES;$j++)
    {
        print "j is $j and process_state_list is $process_state_list{$j}\n";
    if ($process_state_list{$j}=~ /INACTIVE/)
    {
        $process_state_list{$j}="ACTIVE";
        return $j;
    }
    }
  }
}
sub PARENT_create_child()
{
    for (my $i=0;$i<$MAX_PROCESSES;$i++)
     {
        print"--------FORKING CHILD from MAIN PROCESS MAIN PID $$\n";
        my $local_pr_id = PARENT_update_child_map($i,"CREATE");
        my $pid = fork() ;
                if ($pid) {
        # parent
        print "For local_pr_id $local_pr_id CHILD is $pid, PARENT $$\n";
        $ACTIVE_PROCESSES++;
                } 
        elsif ($pid == 0) {
                # child
                child_activator($local_pr_id);
        exit 0;
        } else {
                die "couldnt fork: $!\n";
        }
      }
}
sub PARENT_create_child_listener()
{
print"--------THREADING CHILD LISTENER FROM--$$--\n";
my $i;
for ($i=0;$i<$MAX_PROCESSES;$i++)
{
my $worker_thread = threads->create(sub {\&read_from_child($i)});
$worker_thread->detach();
}
}
sub read_from_child
{
    my $th=threads->self();
    print"--------NOW THREADING:$th->tid()\n";
    my ($pipe_index)=shift;
    print "pipe_index is $pipe_index\n";
    ($pipe_array[$pipe_index])->reader();
    my $filehandle=$pipe_array[$pipe_index];
    while ( <$filehandle> ) {
        my $msg=$_;
        print "CHILD LISTENER received: $msg And current Process ID is $$\n";
        PARENT_msg_from_child($msg);
    }
    print "Exiting read_from_child from $$\n";
}
sub PARENT_msg_from_child()
{
my $msg=shift;
if ($msg =~ /IPC_MSG_PROCESS_EXIT/)
  {
   PARENT_handle_IPC_MSG_PROCESS_EXIT($msg);
  }
if ($msg=~ /IPC_MSG_PROCESS_START/)
  {
   PARENT_handle_IPC_MSG_PROCESS_START($msg);
  }
}
sub PARENT_handle_IPC_MSG_PROCESS_START
{
my $msg=shift;
my @split_array=split(":",$msg);
my $local_pr_id=$split_array[1];
my $process_id=$split_array[2];
$process_state_list{$local_pr_id}="ACTIVE";
$process_id_list{$local_pr_id}=$process_id;
}
sub PARENT_handle_IPC_MSG_PROCESS_EXIT
{
my $msg=shift;
my @split_array=split(":",$msg);
my $local_pr_id=$split_array[1];
print "------------------------\n";
$ACTIVE_PROCESSES--;
$process_state_list{$local_pr_id}="INACTIVE";
my $exists = kill 0, $local_pr_id;
kill(9,$process_id_list{$local_pr_id}) if $exists;
print "Process $process_id_list{$local_pr_id} terminated\n";
}
sub spawn_next_process
{
my $local_pr_id= shift;
print"--------FORKING NEXT CHILD from MAIN PROCESS MAIN PID $$\n";
        $process_state_list{$local_pr_id}="ACTIVE";
        my $pid = fork() ;
                if ($pid) {
        # parent
        print "For local_pr_id $local_pr_id CHILD is $pid, PARENT $$\n";
        $ACTIVE_PROCESSES++;
                } 
        elsif ($pid == 0) {
                # child
                child_activator($local_pr_id);
        exit 0;
        } else {
                die "couldnt fork: $!\n";
        }
}
#################C H I L D -- S E C T I O N####################
sub child_activator {
        sleep (7);
        my $local_pr_id=shift;
        print "In child activator $$\n";
        my $filehandle=$pipe_array[$local_pr_id] ;
        ($pipe_array[$local_pr_id])->writer();
        my $message="IPC_MSG_PROCESS_START:$local_pr_id:$$:";
    print "Sending $message\n";
        print $filehandle $message
            or die "Failed to pass message to child: $!";
        my $random_number = rand();
        sleep(4*$random_number);
        print "Now in child process $$\n";
        print "local_pr_id is $local_pr_id\n";
        $message="IPC_MSG_PROCESS_EXIT:$local_pr_id:";
        print "Sending $message\n";
        print $filehandle $message
            or die "Failed to pass message to child: $!";
}
################# E N D - C H I L D - S E C T I O N###########

我从中得到的输出非常奇怪:-

<I>xl-mat-02{userxxx}141: perl run_tc.pl
Starting main program
Pipe 0 initialized to IO::Pipe=GLOB(0x169c4830)
Pipe 1 initialized to IO::Pipe=GLOB(0x168632a0)
Pipe 2 initialized to IO::Pipe=GLOB(0x169c4af0)
Pipe 3 initialized to IO::Pipe=GLOB(0x169c4bb0)
Pipe 4 initialized to IO::Pipe=GLOB(0x169c4c70)
Spawn process called..
--------FORKING CHILD from MAIN PROCESS MAIN PID 1520
j is 0 and process_state_list is INACTIVE
For local_pr_id 0 CHILD is 1598, PARENT 1520
--------FORKING CHILD from MAIN PROCESS MAIN PID 1520
j is 0 and process_state_list is ACTIVE
j is 1 and process_state_list is INACTIVE
For local_pr_id 1 CHILD is 1599, PARENT 1520
--------FORKING CHILD from MAIN PROCESS MAIN PID 1520
j is 0 and process_state_list is ACTIVE
j is 1 and process_state_list is ACTIVE
j is 2 and process_state_list is INACTIVE
For local_pr_id 2 CHILD is 1600, PARENT 1520
--------FORKING CHILD from MAIN PROCESS MAIN PID 1520
j is 0 and process_state_list is ACTIVE
j is 1 and process_state_list is ACTIVE
j is 2 and process_state_list is ACTIVE
j is 3 and process_state_list is INACTIVE
For local_pr_id 3 CHILD is 1601, PARENT 1520
--------FORKING CHILD from MAIN PROCESS MAIN PID 1520
j is 0 and process_state_list is ACTIVE
j is 1 and process_state_list is ACTIVE
j is 2 and process_state_list is ACTIVE
j is 3 and process_state_list is ACTIVE
j is 4 and process_state_list is INACTIVE
For local_pr_id 4 CHILD is 1602, PARENT 1520
--------THREADING CHILD LISTENER FROM--1520--
--------NOW THREADING:threads=SCALAR(0x16abfef0)->tid()
pipe_index is 0
--------NOW THREADING:threads=SCALAR(0x16b95010)->tid()
pipe_index is 1
--------NOW THREADING:threads=SCALAR(0x2aaaac0fdfb0)->tid()
pipe_index is 2
--------NOW THREADING:threads=SCALAR(0x2aaaac1e2770)->tid()
pipe_index is 3
--------NOW THREADING:threads=SCALAR(0x2aaaac2c7210)->tid()
pipe_index is 4
In child activator 1598
Sending IPC_MSG_PROCESS_START:0:1598:
In child activator 1599
Sending IPC_MSG_PROCESS_START:1:1599:
In child activator 1600
Sending IPC_MSG_PROCESS_START:2:1600:
In child activator 1601
Sending IPC_MSG_PROCESS_START:3:1601:
In child activator 1602
Sending IPC_MSG_PROCESS_START:4:1602:
Now in child process 1599
local_pr_id is 1
Now in child process 1600
local_pr_id is 2
Sending IPC_MSG_PROCESS_EXIT:2:
Sending IPC_MSG_PROCESS_EXIT:1:
Now in child process 1601
local_pr_id is 3
Sending IPC_MSG_PROCESS_EXIT:3:
***Segmentation fault***
xl-mat-02{userxxx}142: Now in child process 1598
local_pr_id is 0
Sending IPC_MSG_PROCESS_EXIT:0:
Now in child process 1602
local_pr_id is 4
Sending IPC_MSG_PROCESS_EXIT:4:</I>

我无法发现为什么会出现分段错误。就像我说的,我是在多进程环境中编程的新手。所以我可能错过了一些非常基本的东西。任何帮助,将不胜感激。即使您对这种情况下的分段错误有一些基本提示,也请告诉我,因为我一无所知!

4

0 回答 0