【问题标题】:BASH adding a slot_id to this background process managerBASH 将 slot_id 添加到此后台进程管理器
【发布时间】:2014-10-07 21:27:36
【问题描述】:

编辑:我在这里简化我的问题:BASH local and flock

我设法创建了一个启动后台进程的管理器。 目的是:

  • 启动管理器并仅启动 nb_min(示例 1)子进程(本示例中为 python 文件)。
  • 如果子进程以 0 错误代码结束,则升级到 nb_max(示例 10)子进程
  • 否则仅重新启动 nb_min (1) 进程

所以我只会在 nb_min 和 nb_max 之间同时启动子进程

现在,我想为每次启动添加一个 id 插槽,以确保我只有 1 个使用相同 id_slot 运行的调用...我不知道如何管理这个!

这里是 manager.sh 代码:

#!/bin/bash

if [ "$USER" != "root" ]
then
        echo "erreur"
        echo "il faut lancer ce script en root"
        echo "sudo $0 nb_jobs_depart nb_jobs_max command"
        exit 1
fi

if [[ $# < 3 ]]
then
        echo "erreur"
        echo "il faut au moins 3 parametres"
        echo "sudo $0 nb_jobs_depart nb_jobs_max command"
        exit 1
fi


min_jobs=$1
shift
max_jobs=$1
shift
command=$@

#n_job=$min_job
echo $min_jobs>/dev/shm/n_job

function _job_worker()
{
        local command=$@
        local result=

        echo "lancement de $command"

        #{ $command ; } >>./_logme.log 2>&1
        $command >>./_logme.log 2>&1
        local result=$?
        echo "retour de command : $result"
        if [[ "${result}" == "0" ]]; then
                echo $max_jobs>/dev/shm/n_job
                #n_job=$max_jobs
                echo "passage a $max_jobs jobs"
        else
                echo $min_jobs>/dev/shm/n_job
                #n_job=$min_jobs
                echo "passage a $min_jobs jobs"
        fi
}

while true; do
        n_job=$(</dev/shm/n_job)
        current_jobs=$(jobs -pr)
        x=0;
        for job in $current_jobs; do
                (( x++ ))
        done;

        echo "il y a $x jobs en cours, il en faut $n_job"
        jobs_to_run=$(($n_job - $x))
        if (( jobs_to_run > 0 )); then
                echo "il y a $jobs_to_run a relancer"
                for (( y = 0; y < $jobs_to_run; y++ )); do
                        _job_worker $command &
                done
        fi
        x=0
        echo "petite pause"
        jobs
        sleep 1
done

这是用于测试的 python 代码,使用 2 个参数调用:

  1. 几秒钟后暂停
  2. 退出代码

示例:./sleeper.pl 10 0 启动 10 秒的暂停并返回错误代码 0

#!/usr/bin/perl -w

use strict;

my $time = $ARGV[0] || 1;
my $exit = $ARGV[1] || 0;

print "bonjour $time $exit \n";

sleep $time;
exit $exit;

现在是代码示例:

./manager.sh 1 10 ./sleeper.pl 10 0
  • 如果错误码 == 0,则调用最少 1 个进程,最多 10 个进程
  • 每个进程调用 sleeper.pl,暂停 10 秒,返回码为 0

编辑:16h30

我试图从这里管理共享数组建议:bash background process modify global variable

但是后来被锁的问题撞到了,女巫我试图用羊群覆盖,但后来我松开了锁和之后的 z 局部变量......

这个新版本尝试使用每个孩子的 pid ...但现在我总是得到相同的 PID ...????....

#!/bin/bash

if [ "$USER" != "root" ]
then
        echo "erreur"
        echo "il faut lancer ce script en root"
        echo "sudo $0 nb_jobs_depart nb_jobs_max command"
        exit 1
fi

if [[ $# < 3 ]]
then
        echo "erreur"
        echo "il faut au moins 3 parametres"
        echo "sudo $0 nb_jobs_depart nb_jobs_max command"
        exit 1
fi


min_jobs=$1
shift
max_jobs=$1
shift
command=$@

#n_job=$min_job
echo $min_jobs>/dev/shm/n_job

declare -A SLOTS
for (( y = 1; y <= $min_jobs; y++ )); do
    SLOTS[$y]="vide"
done
set | grep ^SLOTS= >/dev/shm/SLOTS

declare -A PIDS

exists(){
  if [ "$2" != in ]; then
    echo "Incorrect usage."
    echo "Correct usage: exists {key} in {array}"
    return
  fi   
  eval '[ ${'$3'[$1]+muahaha} ]'  
}


function _job_worker()
{
    local command=$@
    local z=1
    local result=

    # je dois trouver un slot dispo
    echo "avant le lock mon pid vaut $$"
    (
        # Wait for lock on /var/lock/.manager.exclusivelock (fd 200)
        flock -x -w 10 200 || return

        echo "apres le lock mon pid vaut $$"

        declare -A SLOTS;
        . /dev/shm/SLOTS

        echo "DEBUG etat des slots AVANT process"
        dumpSLOTS

        for i in "${!SLOTS[@]}"
        do
            if [[ "${SLOTS[$i]}" != "vide" ]]; 
            then
                z=$(( $z + 1 )) 
                echo "z vaut $z"
                if [[ $z -gt $n_job ]]; then
                    echo "ERREUR tous les slots sont plein ...."
                    exit 9
                fi
            fi
        done

        echo "je remplie le slot $z avec le pid $$"
        SLOTS[$z]=$$
        PIDS[$$]=$z
        # je sauve
        set | grep ^SLOTS= >/dev/shm/SLOTS
    ) 200>/var/lock/.manager.exclusivelock

    echo "mon pid est $$ je cherche le slot qui correspond"
    local my_slot=$PIDS[$$]
    echo "lancement de $command sur le slot $my_slot"
    $command $my_slot >>./_logme.log 2>&1
    result=$?
    # je recharge la liste des slots
    . /dev/shm/SLOTS

    echo "retour de command : $result"
    if [[ "${result}" == "0" ]]; then
            echo $max_jobs>/dev/shm/n_job
            #n_job=$max_jobs
            echo "passage a $max_jobs jobs"
            for (( y = 1; y <= $max_jobs; y++ )); do
                #if ! exists $y in $SLOTS; then SLOTS[$y]="vide"; fi
                if [ ! ${SLOTS[$y]+existe} ] ;
                then 
                    SLOTS[$y]="vide"; 
                fi
            done
    else
            echo $min_jobs>/dev/shm/n_job
            #n_job=$min_jobs
            echo "passage a $min_jobs jobs"
    fi

    # je vide le slot
    SLOTS[$my_slot]="vide"

    # je sauve
    (
        # Wait for lock on /var/lock/.manager.exclusivelock (fd 200)
        flock -x -w 10 200 || return

        # je sauve
        set | grep ^SLOTS= >/dev/shm/SLOTS
    ) 200>/var/lock/.manager.exclusivelock

    echo "etat des slots APRES process"
    dumpSLOTS

    sleep .3;
}

function dumpSLOTS() {
    declare -A SLOTS;
    . /dev/shm/SLOTS
    printf "%12s" ${!SLOTS[@]}
    echo
    printf "%12s" ${SLOTS[@]}
    echo
}


while true; do

    echo "le pid du process pere est $$"

    n_job=$(</dev/shm/n_job)
    current_jobs=$(jobs -pr)
    x=0;
    for job in $current_jobs; do
            (( x++ ))
    done;

    echo "il y a $x jobs en cours, il en faut $n_job"
    jobs_to_run=$(($n_job - $x))
    if (( jobs_to_run > 0 )); then
            echo "il y a $jobs_to_run a relancer"
            for (( y = 0; y < $jobs_to_run; y++ )); do
                    echo " je lance"
                    _job_worker $command & 2>&1 | tee 
            done
    fi
    x=0
    echo "etat des jobs"
    jobs
    echo "etat des slots"
    dumpSLOTS
    echo "etat des PIDS"
    printf "%12s" ${!PIDS[@]}
    echo
    printf "%12s" ${PIDS[@]}
    echo
    sleep 1
done

【问题讨论】:

    标签: bash background subprocess slot


    【解决方案1】:

    根据http://wiki.bash-hackers.org/howto/mutex 的建议来管理潜在的并发问题。

    我的提议有点难看,但应该可行(简单的方法):

    • 通过创建文件夹/dev/shm/my_jobs 来初始化脚本。此文件夹将包含从 1$max_jobs 的文件
    • 在 shell_exec $command &gt;&gt;./_logme.log 2&gt;&amp;1 之前,执行:
      • 创建一个变量i=0 并从1 到$max_jobs 进行测试,直到找到合适的$i,因为/dev/shm/my_jobs/$i 不存在并且mkdir /dev/shm/my_jobs/$i 成功(f mkdir 失败,这意味着另一个_job_worker 已同时创建文件夹)
    • 在 shell_exec $command &gt;&gt;./_logme.log 2&gt;&amp;1 之后,执行:
      • 删除/dev/shm/my_jobs/$i

    这样做的问题是查找$i 和创建/dev/shm/my_jobs/$i 必须一起完成。如果无法锁定这两条指令,您可能会遇到并发问题。

    【讨论】:

    猜你喜欢
    • 2015-10-03
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多