2010-06-03 7 views

Respuesta

5

La forma estándar de hacer esto es crear un archivo pid en alguna parte, que generalmente contiene el pid de su programa.

No necesita poner el pid allí, simplemente podría ponerle un candado exclusivo. Si lo abre para leer/escribir y lo agrupa con LOCK_EX | LOCK_NB, fallará si el archivo ya está bloqueado. Esto es libre de condición de carrera y el bloqueo se liberará automáticamente si el programa falla.

Normalmente, querrá hacerlo por usuario, por lo que el directorio de inicio del usuario es un buen lugar para guardar el archivo.

Si es un daemon, en algún lugar como/var/run es mejor.

4

Puede usar archivos y bloqueos de archivos para lograr esto, pero tenga cuidado de que no sea perfecto y no copie el infame error de Firefox donde se niega a arrancar a veces incluso si no se está ejecutando.

La lógica básica de la misma es:

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 

Además de la lógica anterior, también debe utilizar un segundo archivo que se bloquea con el fin de sincronizar el acceso al archivo PID (esto es, actuar como una mutex para que sea seguro en términos de concurrencia a nivel de proceso).

+0

¿No sería más sencillo utilizar un socket en lugar de un archivo e intentar vincularlo a un puerto predefinido? Y, por cierto, ¿por qué no puedo usar el bloqueo de archivos sin toda la verificación pid? – jackhab

+0

@Jack, puedes hacerlo sin verificación PID, pero luego corres el riesgo de asumir que el programa está abierto cuando se ha bloqueado y no ha podido limpiar el archivo (piensa en el problema de Firefox). Además, Rakis plantea un buen punto, que es que, en Linux, puede verificar que el PID pertenece a su programa utilizando los datos en '/ proc' ... hay formas programáticas de hacerlo de manera más genérica en las variantes de UNIX (como mínimo, podría invocar "ps" y analizar su salida, aunque creo que puede haber funciones que pueda invocar para obtener la información del proceso directamente). –

+1

para verificar la existencia de un proceso, call kill (pid, 0). Esto tiene éxito cuando existe el proceso; de lo contrario, falla. ¡Tenga cuidado con el proceso que se ejecuta en una máquina diferente! – Arkadiy

1

Una alternativa relacionada a la solución de Michael es crear un directorio en una ubicación conocida (probablemente en/var/run o/tmp) y utilizar el éxito/fracaso de la llamada del sistema como mecanismo para garantizar la exclusión mutua. Este es el mismo truco de exclusión mutua que CVS ha utilizado durante años, ya que la creación de directorios es atómica en la mayoría (quizás todos) de los sistemas operativos básicos. Un archivo PID sigue siendo útil en el caso en que el proceso de creación de directorio + PID falle inesperadamente y no se pueda limpiar. Además, cuando verifique si el directorio + PID existente es válido, sugeriría que se verifique explícitamente el enlace simbólico /proc/<PID>/exe para verificar que apunta a su ejecutable en lugar de solo suponer que el PID no se ha reciclado.

-1

Puede usar POSIX named semaphore para hacerlo. Es mucho más seguro que usar un bloqueo de archivos.

+0

¿Cómo lidia con un programa que se colgó sin limpiar el semáforo? –

+0

desde la página man: los semáforos con nombre POSIX tienen persistencia del kernel: si no lo elimina sem_unlink(), existirá un semáforo hasta que se cierre el sistema. Crash definitivamente será un problema aquí. – jackhab

0

Para una aplicación de escritorio, probablemente sea más factible comprobar si se inicia una instancia para usuario actual, de modo que dos usuarios puedan tener sus propias instancias ejecutándose.

Puede usar algunas bibliotecas (libunique (GTK +) o QtSingleApplication (Qt)), o hágalo usted mismo. Además del archivo pid mencionado anteriormente, puede abrir un socket FIFO o dominio UNIX en algún lugar del directorio de inicio del usuario. De esta manera, podría comunicarse con la instancia en ejecución, por ej. elevar la ventana de la instancia en ejecución o indicar a la instancia en ejecución que abra un nuevo archivo/URI/lo que sea.

Cuestiones relacionadas