2013-04-03 11 views
13

Ho 10 processi che tentano di aprire lo stesso file più o meno allo stesso tempo usando la chiamata aperta (O_CREAT), quindi cancellarla. Esiste un modo efficace per scoprire quale processo ha effettivamente creato il file e che ha già aperto il file di creazione, ad esempio, se voglio contare con precisione quante volte quel file è stato aperto in tale scenario.aperto con O_CREAT - è stato aperto o creato?

Immagino di poter inserire un mutex globale sull'operazione di apertura dei file e di eseguire una sequenza di chiamate open() utilizzando i flag O_CREAT e O_EXCL, ma ciò non corrisponde alla mia definizione di "robusto".

+3

Utilizzare '(O_CREAT | O_EXCL)' per ottenere un errore se il file esiste già. Quando si verifica l'errore, si controlla l'errore "errno" per vedere se è perché esiste, quindi riaprire comunque se si desidera aprirlo, sapendo che esiste già. – jxh

+0

E poi fare cosa? Ma cosa succede se un altro processo lo apre dopo il mio controllo ma prima che il mio "riapri comunque"? – Sergey

+0

Il tuo problema nella descrizione non è completamente specificato allora. Aggiorna la tua domanda con il problema reale che stai affrontando. Mostra del codice e indica dove qualcosa non sta accadendo nel modo in cui ti aspetti. – jxh

risposta

2

base all'incirca sui vostri commenti, si desidera qualcosa sulla falsariga di questa funzione:

/* return the fd or negative on error (check errno); 
    how is 1 if created, or 0 if opened */ 
int create_or_open (const char *path, int create_flags, int open_flags, 
        int *how) { 
    int fd; 
    create_flags |= (O_CREAT|O_EXCL); 
    open_flags &= ~(O_CREAT|O_EXCL); 
    for (;;) { 
     *how = 1; 
     fd = open(path, create_flags); 
     if (fd >= 0) break; 
     if (errno != EEXIST) break; 
     *how = 0; 
     fd = open(path, open_flags); 
     if (fd >= 0) break; 
     if (errno != ENOENT) break; 
    } 
    return fd; 
} 

Questa soluzione non è a prova di proiettile. Ci possono essere casi (collegamenti simbolici forse?) Che causerebbero un loop infinito. Inoltre, potrebbe attivare il live lock in determinati scenari di concorrenza. Lascerò risolvere questi problemi come un esercizio. :-)


Nella tua domanda modificato, si pongono:

ho 10 processi che tentano aprire lo stesso file più o meno allo stesso tempo utilizzando aperta chiamata (O_CREAT), quindi eliminare esso.

Un hack-ish, ma più a prova di proiettile, la soluzione sarebbe quella di dare a ciascun processo un ID utente diverso. Quindi, usa semplicemente la normale chiamata open(path, O_CREAT|...). È quindi possibile interrogare il file con fstat() sul descrittore di file e controllare il campo st_uid della struttura stat. Se il campo è uguale all'ID utente dei processi, è stato il creatore. Altrimenti, era un apripista. Funziona poiché ogni processo cancella il file dopo l'apertura.

+0

Per combattere il live-lock, mi piacerebbe ricorrere a una sorta di mutex globale condiviso dopo alcune iterazioni. Ma poi la soluzione diventa qualcosa che speravo di evitare. – Sergey

+0

Accetto questa risposta poiché questo è il più vicino a quello che volevo ottenere. – Sergey

6

Utilizzare la bandiera O_EXCL con O_CREAT. Questo fallirà se il file esiste e errno sarà impostato su EEXIST. Se fallisce , tentare nuovamente l'apertura senza O_CREAT e senza le modalità O_EXCL.

ad es.

int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); 
if ((fd == -1) && (EEXIST == errno)) 
{ 
    /* open the existing file with write flag */ 
    fd = open(path, O_WRONLY); 
} 
+0

puoi chiarire "tenta di aprire di nuovo senza O_CREAT". Se ometto O_CREAT dal tuo codice, rimarrò solo con O_EXCL e accetterò [this] (http://linux.die.net/man/2/open) "In generale, il comportamento di O_EXCL non è definito se è usato senza O_CREAT ". – Sergey

+0

Se la creazione di O_EXCL fallisce perché EEXISTS, riprovare senza _'O_EXCL'_ e senza _'O_CREAT'_! Nota che quando hai O_CREAT, 'open()' accetta 3 argomenti; la terza è la modalità permessi per i file (0644 o simile). È necessario anche uno di O_RDONLY, O_WRONLY o O_RDWR (anche se la loro omissione è equivalente a O_RDONLY, ma la creazione di un file in modalità di sola lettura è modestamente inutile). –

+0

Ho modificato il post che, si spera, chiarirà. – suspectus