flock
выполняет рекомендательную блокировку, которая представляет собой схему совместной блокировки. Это означает, что вы сможете обойти блокировку, если не будете сотрудничать. Вы сотрудничаете, запрашивая блокировку перед выполнением операции, а затем освобождая блокировку после того, как закончите. Это операция, которая защищена блокировкой, а не (обязательно )самим файлом блокировки.
Из руководства flock(2)
по моей системе:
Advisory locks allow cooperating processes to perform consistent operations on files, but do not guarantee consistency (i.e., processes may still access files without using advisory locks possibly resulting in inconsistencies).
Рассмотрим этот скрипт:
#!/bin/sh
( flock -x 9 || exit 1
echo '1: Locking for 5 secs'; sleep 5; echo '1: Done' ) 9>/tmp/lock &
sleep 1
echo '2: Will now attempt to get lock'
( flock -x 9 || exit 1
echo '2: Got lock' ) 9>/tmp/lock
# Since the second flock call only performs one operation, the whole last
# subshell may be replaced by just
# flock -x /tmp/lock -c echo '2: Got lock'
#
# (-x and -c are not needed, a lock is exclusive ("write lock")
# unless -s is used to create a shared lock ("read lock"),
# and the -c is optional)
Выход:
1: Locking for 5 secs
2: Will now attempt to get lock
1: Done
2: Got lock
Вы можете видеть, что блокировка была получена фоновым процессом и что другой flock
вызов должен был дождаться ее освобождения, прежде чем смог заблокировать ее.
Также обратите внимание, что здесь защищен не файл блокировки, а echo
операции в подоболочках, которые гарантированно являются монопольными. В частности, файл блокировки не защищен от несговорчивых процессов, выполняющих запись или чтение из него.
Это означает, что каждой flock
субоболочке путем блокировки /tmp/lock
в этом примере гарантируется, что операции (над файлами или другими общими ресурсами данных )не будут смешиваться с конфликтующими операциями из любого другая программа, которая использует flock
с /tmp/lock
в качестве файла блокировки.
Чтобы проиллюстрировать последний абзац выше, запустите мой сценарий выше на двух разных терминалах (, возможно, с немного увеличенным временем ожидания ), как можно одновременно, и убедитесь, что два конкурирующих сценария правильно получают блокировки (ждут друг друга ). Поскольку одна блокировка запрашивается в фоновом процессе,это означает, что блокировки могут быть получены не в порядке, указанном в сценарии, при одновременном запуске двух экземпляров сценария.
В вашем примере интерактивная оболочка не взаимодействует с механизмом блокировки . Вот почему вы можете читать и записывать в файл, даже если блокировка удерживается фоновой подоболочкой.
Также обратите внимание, что не все файловые системы могут поддерживать блокировку файлов с помощьюflock
(или его эквивалента в библиотеке C,flock()
). Например, сетевые файловые системы AFS и NFS могут быть проблематичными в этом отношении. См.https://en.wikipedia.org/wiki/File_locking#Problems
Я еще немного покопался и обнаружил, что у команды ss
есть несколько полезных функций:
-E
дает нам поток событий, но кажется, что он полезен только с соединениями TCP. Мы можем считать установленные и закрытые соединения, но ничего не печатается с соединениями udp.
Но мы можем проверить значения Recv -Q при использованииss -una state all '( sport = :<port> )'
Если он остается равным 0 достаточно долго, мы можем отменить приоритет процесса, а если он больше нуля, мы можем установить приоритет процесса.
В итоге я написал сценарий:
#!/bin/bash
state=idle
count=0
fstate=idle
ramptime=3
pid=$1
port=$2
while true; do
while [ $count -lt $ramptime ]; do
sleep 1
activity=$(ss -unHa state all '( sport = :'$port' )' | awk '{ print $2 };')
if [ $activity -eq 0 ]; then
fstate=idle
else
fstate=active
fi
if [ $fstate = $state ]; then
count=0
else
count=$((count+1))
fi
#echo $activity $count $state $fstate
done
count=0
state=$fstate
case $state in
idle)
ramptime=3
schedtool -D $pid
renice 20 -p $pid
ionice -c 3 -p $pid
;;
active)
ramptime=30
schedtool -R -p 1 $pid
renice -10 -p $pid
ionice -c 2 -p $pid
esac
done