Qual è il modo migliore per impedire che un programma/demone Linux venga eseguito più volte in un dato momento?Come impedire a un programma Linux di essere eseguito più di una volta?
risposta
Il modo più comune è quello di creare un file PID: definire una posizione in cui il file andrà (dentro/var/run è comune). In caso di avvio riuscito, scriverai il tuo PID in questo file. Al momento di decidere se avviarsi, leggere il file e verificare che il processo di riferimento non esista (o se lo fa, che non è un'istanza del demone: su Linux, è possibile consultare /proc/$PID/exe
). All'arresto, è possibile rimuovere il file ma non è strettamente necessario.
Ci sono degli script per aiutarti a fare questo, potresti trovare utile start-stop-daemon
: può usare i file PID o anche solo verificare globalmente l'esistenza di un eseguibile. È stato progettato proprio per questo compito ed è stato scritto per aiutare le persone a farlo bene.
Se si ha accesso al codice (cioè sono scriverlo):
- creare un file temporaneo, bloccarlo, rimuovere una volta fatto,
return 1;
se file esiste, o, - processi lista,
return 1;
se il nome del processo è nella lista
Se non lo fai:
- creat e un wrapper di avvio per il programma che fa uno dei precedenti
Ok , sembra interessante. Ma cosa succede se il processo viene ucciso prima che possa rimuovere il file temporaneo? –
Questo è un problema, si. Potresti usare il secondo metodo per evitare questo problema, comunque. –
Oppure un normale file come 'application.pid' su cui ottenere un blocco esclusivo, che alla fine dell'applicazione sarebbe stato rilasciato. – mhitza
Non so quale sia il vostro esatto requisito ma ho avuto un requisito simile; in quel caso ho avviato il mio demone da uno script Shell (era una macchina HP-UX) e prima di avviare il demone ho controllato se un exec con lo stesso nome è già in esecuzione. Se è; quindi non iniziare uno nuovo.
In questo modo sono stato anche in grado di controllare il numero di istanze di un processo.
e come si controlla se "un exec con lo stesso nome è già in esecuzione"? – phunehehe
È possibile elencare i processi in esecuzione utilizzando il comando 'ps'. Almeno in HP-UX. – Vaibhav
Ho uno script che funziona così. È molto utile, ma è impossibile farlo in modo affidabile. Per esempio. se exec è uno script, quello che vedrai in esecuzione è l'interprete (sh, o perl o qualsiasi altra cosa) e il nome dello script è il primo argomento. Ma è anche possibile eseguire un programma con un nome falso, nel qual caso non si sa come identificarlo. Puoi anche guardare il filesystem/proc. Ma non c'è modo di renderlo affidabile al 100%. – reinierpost
Utilizzare boost interprocess library per creare un blocco di memoria che verrà creato dal processo. Se esiste già, significa che c'è un'altra istanza del processo. Uscita.
Il collegamento più preciso a quello che ti serve è this one.
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/scoped_ptr.hpp>
int main()
{
using boost::interprocess;
boost::scoped_ptr<shared_memory_object> createSharedMemoryOrDie;
try
{
createSharedMemoryOrDie.reset(
new shared_memory_object(create_only, "shared_memory", read_write));
} catch(...)
{
// executable is already running
return 1;
}
// do your thing here
}
Funzionerà se il processo viene ucciso con -9 prima che possa liberare shared_memory_object? – rustyx
penso che questo schema dovrebbe funzionare (ed è anche resistente agli urti):
Presupposto: C'è un file PID per l'applicazione (in genere in/var/run /)
1. Tentare di aprire il file PID
2. Se non esiste, crearlo e scrivere il PID su di esso. Continuare con il resto del programma
3. Se esiste, leggere il PID
4. Se il PID è ancora in esecuzione e è un'istanza del programma, quindi uscire
5. Se il PID non esiste o viene utilizzato da un altro programma, rimuovere il file PID e andare al passaggio 2.
6. Al termine del programma, rimuovere il file PID.
Il ciclo del passaggio 5 garantisce che, se due istanze vengono avviate contemporaneamente, solo una verrà eseguita alla fine.
Non rimuoverei il file pid se non ha il tuo pid in quanto può introdurre una condizione di competizione. – MarkR
Avere un file pid e all'avvio fare un 'kill -0 <pid>'
. Dove è il valore letto dal file. Se la risposta è! = 0, il daemon non è vivo e potresti riavviarlo.
Un altro approccio sarebbe quello di collegarsi a una porta e gestire l'eccezione di bind al secondo tentativo di avviare il demone. Se la porta è in uso, esci altrimenti continua a eseguire il demone.
Il kill -0 ti dirà solo che il processo esiste, non che è il tuo demone. Ho visto un fastidioso bug dove (al momento dell'avvio, dove i numeri pid sono sequenziali) un altro processo prende lo stesso pid e ha causato un errore erroneo all'avvio di un daemon. – MarkR
Credo che la mia soluzione è la più semplice:
(non usarlo se la condizione di corsa è uno scenario possibile, ma in tutti gli altri casi si tratta di una soluzione semplice e soddisfacente)
#include <sys/types.h>
#include <unistd.h>
#include <sstream>
void main()
{
// get this process pid
pid_t pid = getpid();
// compose a bash command that:
// check if another process with the same name as yours
// but with different pid is running
std::stringstream command;
command << "ps -eo pid,comm | grep <process name> | grep -v " << pid;
int isRuning = system(command.str().c_str());
if (isRuning == 0) {
cout << "Another process already running. exiting." << endl;
return 1;
}
return 0;
}
In genere è una buona idea usare 'flock' su un file pid per assicurarsi che il processo che usa il pid sia, di fatto, il tuo. – Hasturkun
Sì, metti un blocco esclusivo sul file pid e lascialo lì. Se il blocco fallisce, è in esecuzione un'altra istanza. – MarkR
Dipende dal fatto che si stia scrivendo il file PID utilizzando il processo daemon o meno: se si utilizza 'start-stop-daemon' o simile, non è possibile bloccare il file in questo modo. Inoltre, anche se riesci a ottenere il blocco, dovresti comunque controllare il PID contenuto nel file, quindi non sono sicuro che ti guadagni molto. –