2012-01-14 13 views
8

Un modo semplice e apparentemente affidabile per fare il bloccaggio sotto bash è:Prevenire blocco propagazione

exec 9>>lockfile 
flock 9 

Tuttavia, bash propaga notoriamente un tale blocco fd a tutta roba biforcuta compresi i programmi eseguiti ecc

C'è un modo per dire a bash di non duplicare il fd? È fantastico che il blocco sia collegato a un file fd che viene rimosso al termine del programma, indipendentemente da come viene interrotto.

so di poter fare cose come:

run_some_prog 9>&- 

Ma questo è abbastanza noioso.

C'è qualche soluzione migliore?

risposta

8

È possibile utilizzare l'opzione -o riga di comando per flock(1) (opzione lunga --close, che potrebbe essere meglio per la scrittura negli script per la natura auto-documentazione) per specificare che il descrittore di file deve essere chiuso prima l'esecuzione di comandi via flock(1):

+0

Thx! Esattamente quello che stavo cercando. – user1050755

+2

Non funziona con 'flock 9', questo è solo per il caso' flock -o lockfile [args ..] ' – Tino

1

Non esiste alcun modo per contrassegnare un FD come close-on-exec all'interno di bash, quindi no, non esiste una soluzione migliore.

1

-o non funziona con i descrittori di file, funziona solo con i file. Devi usare -u per sbloccare il descrittore di file.

Quello che faccio è questa:

# start of the lock sections 
LOCKFILE=/tmp/somelockfile 
exec 8>"$LOCKFILE" 
if ! flock -n 8;then 
     echo Rejected # for testing, remove this later 
     exit   # exit, since we don't have lock 
fi 

# some code which shouldn't run in parallel 

# End of lock section 
flock -u 8 
rm -f "$LOCKFILE" 

In questo modo il descrittore di file verrà chiuso dal processo che ha reso la serratura, e poiché ogni altro processo uscirà, questo significa che solo il processo tenendo la serratura sblocca il descrittore di file e rimuovi il file di blocco.

4

Apparentemente flock -o FD non risolve il problema. Un trucco per liberarsi del superfluo FD per i comandi successivi nello stesso script sia per avvolgere la parte rimanente in una sezione che chiude la FD, in questo modo:

var=outside 

exec 9>>lockfile 
flock -n 9 || exit 
{ 

: commands which do not see FD9 

var=exported 
# exit would exit script 

# see CLUMSY below outside this code snippet 
} 9<&- 
# $var is "exported" 

# drop lock closing the FD 
exec 9<&- 

: remaining commands without lock 

Questo è un po CLUMSY, perché la stretta della FD è così lontana dalla serratura.

È possibile refactoring questo perdere la "naturale" flusso di comando, ma mantenere le cose insieme, che vanno di pari passo:

functions_running_with_lock() 
{ 
: commands which do not see FD9 

var=exported 
# exit would exit script 
} 

var=outside 

exec 9>>lockfile 
flock -n 9 || exit 

functions_running_with_lock 9<&- 

# $var is "exported" 

# drop lock closing the FD 
exec 9<&- 

: remaining commands without lock 

Un po 'di scrittura più bello che mantiene il flusso di comando naturali a scapito di un altro bivio più un ulteriore processo e un flusso di lavoro leggermente diverso, che spesso è utile. Ma questo non permette di impostare le variabili nel guscio esterno:

var=outside 

exec 9>>lockfile 
flock -n 9 || exit 
(
exec 9<&- 

: commands which do not see FD9 

var=exported 
# exit does not interrupt the whole script 
exit 
var=neverreached 
) 
# optionally test the ret if the parentheses using $? 

# $var is "outside" again 

# drop lock closing the FD 
exec 9<&- 

: remaining commands without lock 

A proposito, se si vuole veramente essere sicuri che bash non introduce descrittori di file aggiuntivi (a "nascondere" la FD chiuso e saltare un vera forchetta), ad esempio se esegui dei demoni che poi terrebbero il blocco per sempre, quest'ultima è raccomandata, solo per essere sicuri. lsof -nP e strace your_script sono i tuoi amici.