Flocking um filedescriptor em um shell script

4

Eu pensei que isso me daria begin-end pares ininterruptos, mas isso não acontece:

#!/bin/bash
fun()(
    flock 1 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
    echo "$BASHPID begin"
    sleep 1;
    echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait

O que estou fazendo de errado?

    
por PSkocik 28.06.2016 / 22:41

2 respostas

3

O motivo da falha pode ser encontrado em man 2 flock :

Locks created by flock() are associated with an open file description (see open(2)). This means that duplicate file descriptors (created by, for example, fork(2) or dup(2)) refer to the same lock, and this lock may be modified or released using any of these descriptors.

Isso significa que, como todos os seus processos herdam o mesmo descritor de arquivo, quando um deles bloqueia, todos eles o compartilham. E bloquear o mesmo descritor de arquivo duas vezes é um não operacional.

Minha solução usual para coisas assim é bloquear o script em si (embora isso cause problemas se você executar o script várias vezes simultaneamente).

#!/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
    
por 29.06.2016 / 00:08
4

Essa abordagem funciona:

fun()(
  (flock 9 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
   echo "$BASHPID begin"
   sleep 1;
   echo "$BASHPID end"
  ) 9>test
)

Isso garante que o arquivo no qual o bloqueio é mantido não esteja fechado, desde que os comandos que precisam ser protegidos não sejam concluídos. (Obviamente você deve substituir test por algo mais apropriado, por exemplo. usando mktemp .)

    
por 28.06.2016 / 22:54