gpt4 book ai didi

Perl、fork、信号量、进程

转载 作者:行者123 更新时间:2023-12-04 20:54:27 25 4
gpt4 key购买 nike

我需要创建一个程序,该程序将从列表中以随机顺序同时运行 3 个进程,并用信号量一个一个地锁定这些进程,以避免重复。
例如,您有 3 个程序的列表:

@array = ( 1,2,3);
  • perl script.pl 首先运行 2;
  • 随机尝试再次运行 2 并收到错误(因为 2 现在被信号量锁定)。
  • 运行 1。
  • 运行 3。
  • script.pl 等待所有 1,2,3 结束工作,然后自行退出。

  • 到目前为止,这是我的代码:
    #!/usr/bin/perl -w
    use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
    use IPC::Semaphore;
    use Carp ();

    print "Program started\n";

    sub sem {
    #semaphore lock code here
    }

    sub chooseProgram{
    #initialise;
    my $program1 = "./program1.pl";
    my $program2 = "./program2.pl";
    my $program3 = "./program3.pl";
    my $ls = "ls";
    my @programs = ( $ls, $program1, $program2, $program3 );

    my $random = $programs[int rand($#programs+1)];
    print $random."\n";
    return $random;
    }

    #parent should fork child;
    #child should run random processes;
    #avoid process clones with semaphore;
    sub main{
    my $pid = fork();
    if ($pid){
    #parent here
    }
    elsif (defined($pid)){
    #child here
    print "$$ Child started:\n";
    #simple cycle to launch and lock programs
    for (my $i = 0; $i<10; $i++){
    # semLock(system(chooseProgram()); #run in new terminal window
    # so launched programs are locked and cannot be launched again
    }
    }
    else {
    die("Cannot fork: $!\n");
    }
    waitpid($pid, 0);
    my $status = $?;
    #print $status."\n";
    }
    main();
    exit 0;

    问题:
  • 需要锁定文件; (我不知道如何使用信号量。一些锁定文件的尝试失败,因此排除了该代码。)
  • child 等到第一个程序结束后再开始第二个程序。如何让一个 child 同时启动三个程序? (是否有可能或者我应该为一个程序创建一个 child ?)。
  • 程序是非 gui 的,应该在终端中运行。如何在新的终端窗口(选项卡)中运行程序?
  • 没有正确检查 @programs 的所有程序是否都已启动。 - 不太重要。
  • 最佳答案

    你的随机性要求很奇怪,但如果我正确理解了你的要求,你不需要任何类型的锁定来做你想做的事。 (所以 1) 在你的问题中消失了)

    首先打乱程序数组,然后启动该打乱数组的每个命令(这涉及您的 4) )。那么只有 waitpid在你开始一切(处理你的 2) )之后。

    下面的代码就是这样做的,从各种 sleep 开始新终端中的实例(我使用 urxvt ,根据您想要生成的终端进行调整 - 这涉及您的 3) )。

    #! /usr/bin/perl -w
    use strict;
    use warnings;

    my @progs = ("urxvt -e sleep 5", "urxvt -e sleep 2", "urxvt -e sleep 1");
    my @sgrop;
    my @pids;

    # Shuffle the programs
    while (my $cnt = scalar(@progs)) {
    push @sgrop, splice @progs, int(rand($cnt)), 1;
    }

    # Start the progs
    foreach my $prog (@sgrop) {
    my $pid = fork();
    if (!$pid) {
    exec($prog);
    # exec does not return
    } else {
    print "Started '$prog' with pid $pid\n";
    push @pids, $pid;
    }
    }

    # Wait for them
    map {
    waitpid($_, 0);
    print "$_ done!\n";
    } (@pids);

    不确定洗牌是最好的,但它有效。它背后的想法只是从初始(排序)列表中随机选择一个元素,将其从那里删除并将其添加到打乱后的列表中。重复直到初始列表为空。

    如果您尝试在系统范围内锁定程序(即系统中的其他进程不应该能够启动它们),那么很抱歉,除非程序保护自己免受并发执行,否则这是不可能的。

    如果您的问题是关于信号量的,那么很抱歉我错过了您的观点。 IPC documentation有示例代码。不过,我真的认为没有必要为您尝试做的事情考虑那种复杂性。

    以下是使用 IPC::Semaphore 的方法。模块方便。

    在你的 main 开始时,创建一个信号量集,其中包含所需数量的信号量:
    use IPC::SysV qw(S_IRUSR S_IWUSR IPC_CREAT IPC_NOWAIT);
    use IPC::Semaphore;

    my $numprocs = scalar(@progs);
    my $sem = IPC::Semaphore->new(1234, # this random number is the semaphore key. Use something else
    $numprocs, # number of semaphores you want under that key
    S_IRUSR | S_IWUSR | IPC_CREAT);

    检查错误,然后将所有信号量初始化为 1。
    $sem->setall( (1) x $numprocs) || die "can't set sems $!";

    在启动进程的代码中,在开始之前(尽管在 fork 之后),尝试获取信号量:
    if ($sem->op($proc_number, -1, IPC_NOWAIT)) {
    # here, you got the semaphore - so nothing else is running this program
    # run the code
    # and once the code is done:
    $sem->op($proc_number, 1, 0); # release the semaphore
    exit(0);
    } else {
    # someone else is running this program already
    exit(1); # or something
    }

    在上面, $proc_number每个程序必须是唯一的(例如,它可能是程序数组中的索引)。不要使用 exec启动程序。使用 system相反,例如。

    请注意,您将 必须在这种情况下处理子进程的退出代码。如果退出代码为零,您可以将该程序标记为已运行。如果没有,您需要重试。 (这会变得一团糟,您需要跟踪是否运行了哪个程序。我建议您使用程序编号( $proc_number )在其中存储它是否已经完成,以及当前 pid 正在运行(或试图运行)该代码。您可以使用该哈希来确定还需要执行哪个程序。)

    最后,一切都完成了,你已经等了所有的 child ,你应该自己清理一下:
    $sem->remove;

    这段代码缺乏适当的错误检查,如果清理没有正确完成(即代码开始时信号量已经存在),将会奇怪地工作(即根本不好)。但它应该让你开始。

    关于Perl、fork、信号量、进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6168218/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com