2010-06-03 18 views

risposta

5

Il modo standard per eseguire questa operazione è creare un file di pid da qualche parte, in genere contenente il pid del programma.

Non è necessario inserire il pid, è sufficiente inserire un blocco esclusivo. Se lo apri per lettura/scrittura e lo afferro con LOCK_EX | LOCK_NB, fallirà se il file è già bloccato. Questo è privo di condizioni di gara, e il blocco verrà rilasciato automaticamente se il programma si blocca.

Normalmente si vorrebbe farlo per utente, quindi la directory home dell'utente è un buon posto dove mettere il file.

Se è un demone, qualcosa come/var/run è migliore.

4

È possibile utilizzare file e blocchi di file per eseguire questa operazione, ma attenzione non è perfetto e non copiare il famigerato bug di Firefox in cui si rifiuta di avviarsi a volte anche se non è già in esecuzione.

La logica di base di esso è:

Invariant: 
    File xxxxx will exist if and only if the program is running, and the 
    contents of the file will contain the PID of that program. 

On startup: 
    If file xxxxx exists: 
     If there is a process with the PID contained in the file: 
      Assume there is some instance of the program, and exit 
     Else: 
      Assume that the program terminated abnormally, and 
      overwrite file xxxx with the PID of this program 
    Else: 
     Create file xxxx, and save the current PID to that file. 

On termination (typically registered via atexit): 
    Delete file xxxxx 

Oltre alla logica di cui sopra, si dovrebbe anche usare un secondo file che si blocca per sincronizzare l'accesso al file PID (cioè di agire come un mutex per renderlo sicuro in termini di concorrenza a livello di processo).

+0

Non sarebbe più semplice utilizzare un socket anziché un file e provare a collegarsi a una porta predefinita? E, a proposito, perché non posso usare il blocco dei file senza la verifica del pid? – jackhab

+0

@Jack, puoi farlo senza la verifica PID, ma poi corri il rischio di presumere che il programma sia aperto quando si è arrestato in modo anomalo e non è riuscito a ripulire il file (si pensi al problema di Firefox). Inoltre, Rakis porta un buon punto, che è che, su Linux, puoi verificare che il PID appartenga al tuo programma usando i dati in '/ proc' ... ci sono modi programmatici per farlo in modo più generico attraverso le varianti UNIX (come minimo potreste invocare "ps" e analizzare il suo output, anche se credo che ci possano essere funzioni che potete invocare per ottenere direttamente le informazioni sul processo). –

+1

per verificare l'esistenza di un processo, chiamata kill (pid, 0). Questo succede quando il processo esiste, altrimenti fallisce. Attenzione al processo in esecuzione su una macchina diversa! – Arkadiy

1

Un'alternativa correlata alla soluzione di Michael è creare una directory in una posizione nota (probabilmente in/var/run o/tmp) e utilizzare il successo/fallimento della chiamata di sistema come meccanismo per garantire l'esclusione reciproca. Questo è lo stesso trucco di mutua esclusione che CVS ha utilizzato per anni poiché la creazione di directory è atomica sulla maggior parte (forse tutti) dei sistemi operativi di base. Un file PID è ancora utile nel caso in cui la directory + processo di creazione PID muoia in modo imprevisto e non riesca a ripulire. Inoltre, quando si verifica se la directory esistente + PID è valida, suggerisco di verificare esplicitamente il collegamento simbolico /proc/<PID>/exe per verificare che punti al file eseguibile piuttosto che assumere che il PID non sia stato riciclato.

-1

Per eseguire questa operazione è possibile utilizzare POSIX named semaphore. È molto più sicuro dell'utilizzo di un blocco file.

+0

In che modo si tratta di un programma che si è arrestato in modo anomalo senza ripulire il semaforo? –

+0

dalla pagina man: i semafori con nome POSIX hanno la persistenza del kernel: se non viene rimosso da sem_unlink(), un semaforo esisterà fino a quando il sistema non verrà spento. Crash sarà sicuramente un problema qui. – jackhab

0

Per un'applicazione desktop, è probabilmente più possibile verificare se un'istanza viene avviata per utente corrente, in modo che due utenti possano avere le proprie istanze in esecuzione.

È possibile utilizzare una delle due librerie (libunique (GTK +) o QtSingleApplication (Qt)) oppure eseguire da soli. Oltre al file pid menzionato in precedenza, è possibile aprire un socket di dominio FIFO o UNIX da qualche parte nella home directory dell'utente. In questo modo, potresti comunicare con l'istanza in esecuzione, ad es. alzare la finestra dell'istanza in esecuzione o indicare all'istanza in esecuzione di aprire il nuovo file/URI/qualunque.

Problemi correlati