2010-06-18 44 views
4

我已經完成了我以前使用perl線程的多線程程序,它可以在我的系統上運行。問題是,在需要運行的某些系統上,線程支持不會編譯到perl中,我無法安裝其他程序包。因此我需要使用線程以外的東西,並且將我的代碼移動到使用fork()。這在我的Windows系統啓動子任務時起作用。perl多任務問題

的幾個問題:

  1. 如何確定子進程退出時?當線程數低於某個值時,我創建了新線程,我需要跟蹤有多少線程正在運行。對於流程,我如何知道何時退出,以便我可以跟蹤當前存在的數量,在創建時增加計數器,並在退出時遞減計數器?

  2. 當子進程中的父進程安全打開時,使用OPEN獲取的句柄是否是文件I/O?我需要爲每個子進程追加一個文件,這對unix也是安全的。

  3. 是否有任何替代叉和線程?我嘗試使用Parallel :: ForkManager,但未安裝在我的系統上(使用Parallel :: ForkManager;發生錯誤),我絕對要求我的perl腳本可以在所有unix/windows系統上工作,而無需安裝任何其他模塊。

+0

更像是一個工作,但也許你可以每當一個進程開始時,寫一個文件,當它退出刪除文件或類似的東西......有一個主要的腳本來監視這些文件左右...... – Prix 2010-06-18 01:32:43

回答

3

看看waitpid。這裏有一些代碼需要完成九個任務(1到9)。它將啓動三名工人來完成這些任務。

#!/usr/bin/perl 

use strict; 
use warnings; 
use POSIX ":sys_wait_h"; 

my $max_children = 3; 
my %work = map { $_ => 1 } 1 .. 9; 
my @work = keys %work; 

my %pids; 
while (%work) { 
    #while there are still empty slots 
    while (@work and keys %pids < $max_children) { 
     #get some work for the child to do 
     my $work = shift @work; 

     die "could not fork" unless defined(my $pid = fork); 

     #parent 
     if ($pid) { 
      $pids{$pid} = 1; 
      next; 
     } 

     #child 
     print "$$ doing work $work\n"; 
     sleep 1; 
     print "$$ done doing work $work"; 
     exit $work; 
    } 

    my $pid = waitpid -1, WNOHANG; 

    if ($pid > 0) { 
     delete $pids{$pid}; 
     my $rc = $? >> 8; #get the exit status 
     print "saw $pid was done with $rc\n"; 
     delete $work{$rc}; 
     print "work left: ", join(", ", sort keys %work), "\n"; 
    } 

    select undef, undef, undef, .25; 
} 
6

典型用法:在perldoc -f forkwaitpidwaitkillperlipc

use POSIX ':sys_wait_h'; # for &WNOHANG 

# how to create a new background process 
$pid = fork(); 
if (!defined $pid) { die "fork() failed!" } 
if ($pid == 0) { # child 
    # ... do stuff in background ... 
    exit 0;  # don't forget to exit or die from the child process 
} 
# else this is the parent, $pid contains process id of child process 
# ... do stuff in foreground ... 

# how to tell if a process is finished 
# also see perldoc perlipc 
$pid = waitpid -1, 0;   # blocking wait for any process 
$pid = wait;     # blocking wait for any process 
$pid = waitpid $mypid, 0;  # blocking wait for process $mypid 
# after blocking wait/waitpid 
if ($pid == -1) { 
    print "All child processes are finished.\n"; 
} else { 
    print "Process $pid is finished.\n"; 
    print "The exit status of process $pid was $?\n"; 
} 

$pid = waitpid -1, &WNOHANG; # non-blocking wait for any process 
$pid = waitpid $mypid, 0;  # blocking wait for process $mypid 
if ($pid == -1) { 
    print "No child processes have finished since last wait/waitpid call.\n"; 
} else { 
    print "Process $pid is finished.\n"; 
    print "The exit status of process $pid was $?\n"; 
} 

# terminating a process - see perldoc -f kill or perldoc perlipc 
# this can be flaky on Windows 
kill 'INT', $pid;    # send SIGINT to process $pid 

血淋淋的細節。關於爲SIGCHLD事件設置處理程序的perlipc中的內容應該特別有用,儘管Windows不支持該操作。

分叉進程的I/O在Unix和Windows上通常是安全的。文件描述符是共享的,所以這樣的事情

open X, ">", $file; 
if (fork() == 0) { # in child 
    print X "Child\n"; 
    close X; 
    exit 0; 
} 
# in parent 
sleep 1; 
print X "Parent\n"; 
close X; 

兩個孩子,父進程將成功地寫入同一個文件(注意輸出緩衝的,雖然)。