Причину сбоя можно найти в man 2 flock
:
Блокировки, созданные flock (), связаны с описанием открытого файла (см. Open (2)). Это означает, что повторяющиеся файловые дескрипторы (созданные, например, с помощью fork (2) или dup (2)) относятся к одной и той же блокировке, и эта блокировка может быть изменена или снята с использованием любого из этих дескрипторов.
Это означает, что, поскольку все ваши процессы наследуют один и тот же файловый дескриптор, когда один из них выполняет блокировку, все они совместно используют его. И заблокировать один и тот же файловый дескриптор дважды - это не проблема.
Моё обычное решение в подобных случаях - заблокировать сам скрипт (хотя это действительно создает проблемы, если вы запускаете скрипт несколько раз одновременно).
#!/bin/bash
fun()(
exec 3<"$0"
flock 3 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait