написать в fifo / pipe из оболочки с таймаутом - PullRequest
2 голосов
/ 08 января 2009

У меня есть пара программ оболочки, которые общаются по именованному каналу. Считыватель создает канал при его запуске и удаляет его при выходе.

Иногда писатель пытается выполнить запись в канал между временем, когда считыватель прекращает чтение, и временем, когда он удаляет канал.

reader: while condition; do read data <$PIPE; do_stuff; done
writer: echo $data >>$PIPE
reader: rm $PIPE

когда это произойдет, писатель будет висеть навсегда, пытаясь открыть канал для записи.

Есть ли clean способ дать ему тайм-аут, чтобы он не зависал до тех пор, пока его не убьют вручную? Я знаю, что могу сделать

#!/bin/sh
# timed_write <timeout> <file> <args>
# like "echo <args> >> <file>" with a timeout

TIMEOUT=$1
shift;
FILENAME=$1
shift;
PID=$$

(X=0; # don't do "sleep $TIMEOUT", the "kill %1" doesn't kill the sleep
 while [ "$X" -lt "$TIMEOUT" ];
 do sleep 1; X=$(expr $X + 1);
 done; kill $PID) &

echo "$@" >>$FILENAME
kill %1

но это отчасти неприлично. Есть ли встроенная оболочка или команда, делающая это более аккуратно (без отключения компилятора C)?

Ответы [ 4 ]

1 голос
/ 08 января 2009

Стандартный "UNIX" способ справиться с этим - использовать Expect , который поставляется с примером запуска по времени: запускать программу только в течение определенного периода времени.

Expect может творить чудеса в написании сценариев, и его стоит изучить. Если вам не нравится Tcl, есть и модуль Python Expect .

1 голос
/ 08 января 2009

Этот вопрос периодически возникает (хотя я не смог найти его с помощью поиска). Я написал два сценария оболочки для использования в качестве команд тайм-аута: один для вещей, которые читают стандартный ввод, и другой для вещей, которые не читают стандартный ввод. Это воняет, и я намеревался написать программу на C, но я еще не дошел до этого. Я определенно рекомендую написать команду timeout на C раз и навсегда. Но тем не менее, вот более простой из двух сценариев оболочки, который зависает, если команда читает стандартный ввод:

#!/bin/ksh

# our watchdog timeout in seconds
maxseconds="$1"
shift

case $# in
  0) echo "Usage: `basename $0` <seconds> <command> [arg ...]" 1>&2 ;;
esac

"$@" &
waitforpid=$!

{
    sleep $maxseconds
    echo "TIMED OUT: $@" 1>&2 
    2>/dev/null kill -0 $waitforpid && kill -15 $waitforpid
} &
killerpid=$!

>>/dev/null 2>&1 wait $waitforpid
# this is the exit value we care about, so save it and use it when we
rc=$?

# zap our watchdog if it's still there, since we no longer need it
2>>/dev/null kill -0 $killerpid && kill -15 $killerpid

exit $rc

Другой скрипт находится в сети на http://www.cs.tufts.edu/~nr/drop/timeout.

0 голосов
/ 09 декабря 2016
trap 'kill $(ps -L $! -o pid=); exit 30' 30
echo kill -30 $$ 2\>/dev/null | at $1 2>/dev/null
shift; eval $@ &
wait
0 голосов
/ 02 февраля 2009

Эта пара программ работает намного лучше после того, как она была переписана на Perl с использованием доменных сокетов Unix вместо именованных каналов. Конкретная проблема в этом вопросе полностью исчезла, поскольку, если / когда один конец умирает, соединение исчезает, а не зависает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...