tomyamaのブログ

日記・雑記。

FIFOを使ってプロセス間通信する

昔に書いたFIFOを使ってプロセス間通信をするシェルのサンプルスクリプトを見つけた。

 

全然覚えていない。

スクリプト中身を確認すると、FIFOを3つ作って、1つは読み書き用、残り2つは通信する2つのプロセスの状態を通知する為に使っているみたい。通信を5往復すると停止する仕組みになっています。

 

実行結果

$ ./fifo_test.sh
fifo_test.sh: app_KICK(905): begin
fifo_test.sh: app_A(913): begin
fifo_test.sh: app_B(914): begin
seq.0: app_B(914)->app_A(913): I am app_B, 2022/09/11(日) 23:40:18
seq.0: app_A(913)->app_B(914): I am app_A, 2022/09/11(日) 23:40:18
seq.1: app_B(914)->app_A(913): I am app_B, 2022/09/11(日) 23:40:18
seq.1: app_A(913)->app_B(914): I am app_A, 2022/09/11(日) 23:40:19
seq.2: app_B(914)->app_A(913): I am app_B, 2022/09/11(日) 23:40:19
seq.2: app_A(913)->app_B(914): I am app_A, 2022/09/11(日) 23:40:19
seq.3: app_B(914)->app_A(913): I am app_B, 2022/09/11(日) 23:40:19
seq.3: app_A(913)->app_B(914): I am app_A, 2022/09/11(日) 23:40:19
seq.4: app_B(914)->app_A(913): I am app_B, 2022/09/11(日) 23:40:20
seq.4: app_A(913)->app_B(914): I am app_A, 2022/09/11(日) 23:40:20
fifo_test.sh: app_A(913): end
fifo_test.sh: app_KICK(905): collection: app_A(913): fin.
fifo_test.sh: app_B(914): end
fifo_test.sh: app_KICK(905): collection: app_B(914): fin.
fifo_test.sh: app_KICK(905): /tmp/fifo_test.905: remove
fifo_test.sh: app_KICK(905): /tmp/fifo_test.905.A: remove
fifo_test.sh: app_KICK(905): /tmp/fifo_test.905.B: remove
fifo_test.sh: app_KICK(905): end
$

 

シェルスクリプト

[fifo_test.sh]

#!/bin/sh

fi_fifo_basename="fifo_test"
seq_count=5

## script entry point
sh_main ()
{
    sh_init

    arg="$1"
    shift
    if [ $? -ne 0 ]; then
        appid="app_KICK"
    else
        case "$arg" in
            '-a')
                appid="app_A"
                ;;
            '-b')
                appid="app_B"
                ;;
            *)
                perr "$appname: $arg: unknown argument"
                return -1
                ;;
        esac
    fi

    $appid      ## Role playing
    return $?
}

## script setup
sh_init ()
{
    di_work="`pwd`"
    appname="`basename \"$0\"`"
    di_tmp="`dirname  \"$0\"`"
    cd "$di_tmp/"; apppath="`pwd`"; cd "$di_work/"
    unset di_tmp
    pid="$$"
}

## error output
perr ()
{
    echo "$@" 1>&2
}

## user interrupt
func_trap_SIGINT ()
{
    echo "*** Interrupt ***"
#   jobs
#   kill %1
#   kill %2
    for cldpid in `ps -f | awk -v PID="$$" '
            $3==PID {
                print ($2) ;
            }'`; do
#       echo "cldpid=$cldpid"
        kill "$cldpid"
    done

    func_cleanup
}

## wait
func_wait_term ()
{
    cat "$1" | sed "s/^/$appname: $appid($$): collection: /"
}

## notify
func_notify_term ()
{
    echo "$appid($$): fin." > "$1"
}

## app KICK
app_KICK ()
{
    echo "$appname: $appid($$): begin"

    func_initialize

    "$apppath/$appname" "-a" &
    "$apppath/$appname" "-b" &
    trap func_trap_SIGINT SIGINT

#   sleep 3
    func_wait_term "$FI_TERM_A"
    func_wait_term "$FI_TERM_B"
    trap -                SIGINT

    func_cleanup

    echo "$appname: $appid($$): end"
}

## app A
app_A ()
{
    echo "$appname: $appid($$): begin"

    func_check_callseq "$FI_TERM_A"

    idx=0
    while [ $idx -lt $seq_count ]; do
        func_recv
        func_send "I am $appid: `date '+%Y/%m/%d(%a) %H:%M:%S'`"

        idx=`expr $idx + 1`
    done

    echo "$appname: $appid($$): end"
    func_notify_term "$FI_TERM_A"
}

## app B
app_B ()
{
    echo "$appname: $appid($$): begin"

    func_check_callseq "$FI_TERM_B"

    idx=0
    while [ $idx -lt $seq_count ]; do
        func_send "Iam $appid: `date '+%Y/%m/%d(%a) %H:%M:%S'`"
        func_recv

        idx=`expr $idx + 1`
    done

    echo "$appname: $appid($$): end"
    func_notify_term "$FI_TERM_B"
}

## check routine
func_check_callseq ()
{
    notify_fifo="$1"

    if [ "$FI_FIFO" = "" ]; then
        perr "$appname: $appid($$): \$FI_FIFO: undefined"
        perr "$appname: could not call the $arg option directly"
        exit -1
    fi
    if [ ! -p "$FI_FIFO" ]; then
        perr "$appname: $appid($$): $FI_FIFO: fifo not found"
        exit -1
    fi

    if [ "$notify_fifo" = "" ]; then
        perr "$appname: $appid($$): \$notify_fifo: undefined"
        exit -1
    fi
    if [ ! -p "$notify_fifo" ]; then
        perr "$appname: $appid($$): $notify_fifo: fifo not found"
        exit -1
    fi
}

## send
func_send ()
{
    echo "$appid($$): $1" > "$FI_FIFO"
}

## recv
func_recv ()
{
    cat "$FI_FIFO" | sed "s/: /->$appid($$): /" | sed "s/^/seq.$idx: /"
}

## initialize
func_initialize ()
{
    FI_FIFO="/tmp/$fi_fifo_basename.$pid"
    export FI_FIFO
    mkfifo "$FI_FIFO"

    FI_TERM_A="$FI_FIFO.A"
    export FI_TERM_A
    mkfifo "$FI_TERM_A"

    FI_TERM_B="$FI_FIFO.B"
    export FI_TERM_B
    mkfifo "$FI_TERM_B"
}

## cleanup
func_cleanup ()
{
    if [ -p "$FI_FIFO" -o -f "$FI_FIFO" ]; then
        echo "$appname: $appid($$): $FI_FIFO: remove"
        rm -f "$FI_FIFO"
    fi

    if [ -p "$FI_TERM_A" -o -f "$FI_TERM_A" ]; then
        echo "$appname: $appid($$): $FI_TERM_A: remove"
        rm -f "$FI_TERM_A"
    fi

    if [ -p "$FI_TERM_B" -o -f "$FI_TERM_B" ]; then
        echo "$appname: $appid($$): $FI_TERM_B: remove"
        rm -f "$FI_TERM_B"
    fi
}

sh_main "$@"
exit $?