2010-09-14 19 views

Respuesta

20

La forma más común es la creación de un archivo PID: definir una ubicación donde el archivo se va (dentro/var/run es común). En el inicio exitoso, escribirá su PID en este archivo. Cuando decida si iniciar, lea el archivo y verifique para asegurarse de que el proceso al que se hace referencia no existe (o si lo hace, que no es una instancia de su daemon: en Linux, puede mirar /proc/$PID/exe). Al apagarlo, puede eliminar el archivo pero no es estrictamente necesario.

Hay scripts para ayudarlo a hacer esto, puede encontrar que start-stop-daemon es útil: puede usar archivos PID o incluso simplemente verificar globalmente la existencia de un ejecutable. Está diseñado precisamente para esta tarea y fue escrito para ayudar a las personas a hacerlo bien.

+0

Por lo general, es una buena idea usar 'flock' en un archivo pid para garantizar que el proceso que utiliza el pid sea, de hecho, tuyo. – Hasturkun

+0

Sí, ponga un candado exclusivo en el archivo pid y déjelo allí. Si el bloqueo falla, se está ejecutando otra instancia. – MarkR

+0

Eso depende de si está escribiendo el archivo PID usando el proceso del daemon o no: si está usando 'start-stop-daemon' o similar, no puede bloquear el archivo de esa manera. Además, incluso si logras obtener el bloqueo, debes verificar el PID que se encuentra dentro del archivo, así que no estoy seguro de que te haga ganar mucho. –

3

Si usted tiene acceso al código (es decir, está escribiendo):

  • crear un archivo temporal, bloquearla, quite cuando se hace, return 1; si existe el archivo, o,
  • procesos de la lista, return 1; si el nombre del proceso está en la lista

Si no lo hace:

  • creat e un contenedor de iniciador para el programa que hace uno de los anteriores
+0

Ok , eso suena interesante. Pero, ¿qué pasa si el proceso se cancela antes de que pueda eliminar el archivo temporal? –

+0

Eso es un problema, sí. Sin embargo, podría usar el segundo método para evitar este problema. –

+0

O tenga un archivo normal como 'application.pid' para obtener un bloqueo exclusivo, que al final de la aplicación se liberaría. – mhitza

2

No sé cuál es su requisito exacto, pero tenía un requisito similar; en ese caso, inicié mi daemon a partir de un script de Shell (era un equipo HP-UX) y antes de iniciar el daemon comprobé si un ejecutivo con el mismo nombre ya se está ejecutando. Si esto es; entonces no comiences uno nuevo.

De esta manera, también pude controlar el número de instancias de un proceso.

+0

y cómo se verifica si "un ejecutivo con el mismo nombre ya se está ejecutando"? – phunehehe

+0

Puede enumerar los procesos que se ejecutan utilizando el comando 'ps'. Al menos en HP-UX. – Vaibhav

+0

Tengo un script que funciona así. Es muy útil, pero es imposible hacer esto de manera confiable. P.ej. si el ejecutor es un script, lo que verá ejecutar es el intérprete (sh, o perl, o lo que sea) y el nombre del guión es el primer argumento. Pero también es posible ejecutar un programa con un nombre falso, en cuyo caso no sabrá cómo identificarlo. También puede ver el sistema de archivos/proc. Pero no hay forma de que esto sea 100% confiable. – reinierpost

5

Utilice boost interprocess library para crear un bloque de memoria que será creado por el proceso. Si ya existe, significa que hay otra instancia del proceso. Salida.

El enlace más preciso a lo que necesita sería 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 
} 
+1

Funcionará si el proceso se cancela con -9 antes de que pueda liberar shared_memory_object? – rustyx

2

creo que este esquema debería funcionar (y también es robusto frente a los choques):
Condición previa: Hay un archivo PID para su aplicación (normalmente en/var/run /)
1. Trate de abrir el archivo PID
2. Si no existe, créelo y escriba su PID en él. Continuar con el resto del programa
3. Si existe, leer el PID
4. Si el PID sigue en funcionamiento y es una instancia de su programa, a continuación, salga
5. Si no existe el PID o es utilizado por otro programa, elimine el archivo PID y vaya al paso 2.
6. Al finalizar el programa, elimine el archivo PID.

El ciclo en el paso 5 asegura que, si se inician dos instancias al mismo tiempo, solo una se ejecutará al final.

+0

No eliminaría el archivo pid si no tiene su pid, ya que eso puede introducir una condición de carrera. – MarkR

0

Tener un archivo pid y en el inicio hacer un 'kill -0 <pid>'. ¿Dónde se lee el valor del archivo? Si la respuesta es! = 0, entonces el daemon no está activo y puede reiniciarlo

Otro enfoque sería enlazar a un puerto y manejar la excepción de vinculación en el segundo intento de iniciar el daemon. Si el puerto está en uso, salga; de lo contrario, continúe ejecutando el daemon.

+2

El kill -0 solo le dirá que el proceso existe, no que sea su daemon. He visto un error molesto en el que (en el momento del arranque, donde los números de pid son secuenciales), otro proceso toma el mismo pid y hace que un daemon falle al iniciarse. – MarkR

-1

Creo que mi solución es la más sencilla:

(no lo use si la condición de carreras es un escenario posible, pero en cualquier otro caso se trata de una solución sencilla y satisfactoria)

#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; 
} 
Cuestiones relacionadas