tengo saber requerimientos para instalar instalado ejecutar como python linux singleinstance

python - saber - Asegurar una sola instancia de una aplicación en Linux



instalar python en linux (12)

Estoy trabajando en una aplicación de interfaz gráfica de usuario en WxPython, y no estoy seguro de cómo puedo asegurar que solo se ejecute una copia de mi aplicación en un momento dado en la máquina. Debido a la naturaleza de la aplicación, ejecutar más de una vez no tiene sentido y fallará rápidamente. En Win32, puedo simplemente crear un mutex con nombre y verificarlo al inicio. Desafortunadamente, no conozco ninguna instalación en Linux que pueda hacer esto.

Estoy buscando algo que se lanzará automáticamente si la aplicación falla inesperadamente. No quiero tener que cargar a mis usuarios con tener que eliminar manualmente los archivos de bloqueo porque me he caído.


¿Puedes usar la utilidad ''pidof''? Si su aplicación se está ejecutando, pidof escribirá el ID de proceso de su aplicación en stdout. De lo contrario, imprimirá una nueva línea (LF) y devolverá un código de error.

Ejemplo (de bash, por simplicidad):

linux# pidof myapp 8947 linux# pidof nonexistent_app linux#


Aquí está la solución basada en el puerto TCP:

# Use a listening socket as a mutex against multiple invocations import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((''127.0.0.1'', 5080)) s.listen(1)


Busque un módulo de python que interactúe con semáforos SYSV en Unix. Los semáforos tienen una bandera SEM_UNDO que hará que se liberen los recursos mantenidos por el proceso a si el proceso falla.

De lo contrario, como sugirió Bernard, puedes usar

import os os.getpid()

Y escríbalo en / var / run / application_name .pid. Cuando se inicia el proceso, debe verificar si el pid en / var / run / application_name .pid está listado en la tabla ps y salir si lo está, de lo contrario escriba su propio pid en / var / run / application_name .pid. En el siguiente var_run_pid está el pid que lees desde / var / run / application_name .pid

cmd = "ps -p %s -o comm=" % var_run_pid app_name = os.popen(cmd).read().strip() if len(app_name) > 0: Already running


Con mucho, el método más común es soltar un archivo en / var / run / called [application] .pid que contiene solo el PID del proceso en ejecución, o proceso principal. Como alternativa, puede crear un conducto con nombre en el mismo directorio para poder enviar mensajes al proceso activo, por ejemplo, para abrir un archivo nuevo.


Esto se basa en la answer del usuario . Principalmente aborda una complicada preocupación que tiene que ver con el acceso de escritura al archivo de bloqueo. En particular, si el archivo de bloqueo fue creado primero por root , otro usuario foo podrá intentar reescribir este archivo debido a la ausencia de permisos de escritura para el usuario foo . La solución obvia parece ser crear el archivo con permisos de escritura para todos. Esta solución también se basa en una answer diferente por mi parte, teniendo que crear un archivo con dichos permisos personalizados. Esta preocupación es importante en el mundo real, donde su programa puede ser ejecutado por cualquier usuario, incluida la root .

import fcntl, os, stat, tempfile app_name = ''myapp'' # <-- Customize this value # Establish lock file settings lf_name = ''.{}.lock''.format(app_name) lf_path = os.path.join(tempfile.gettempdir(), lf_name) lf_flags = os.O_WRONLY | os.O_CREAT lf_mode = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH # This is 0o222, i.e. 146 # Create lock file # Regarding umask, see https://.com/a/15015748/832230 umask_original = os.umask(0) try: lf_fd = os.open(lf_path, lf_flags, lf_mode) finally: os.umask(umask_original) # Try locking the file try: fcntl.lockf(lf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: msg = (''Error: {} may already be running. Only one instance of it '' ''can run at a time.'' ).format(''appname'') exit(msg)

Una limitación del código anterior es que si el archivo de bloqueo ya existía con permisos inesperados, esos permisos no se corregirán.

Me hubiera gustado usar /var/run/<appname>/ como el directorio para el archivo de bloqueo, pero la creación de este directorio requiere permisos de root . Puede tomar su propia decisión sobre qué directorio usar.

Tenga en cuenta que no es necesario abrir un identificador de archivo para el archivo de bloqueo.


He creado un marco básico para ejecutar este tipo de aplicaciones cuando desea poder pasar los argumentos de la línea de comando de las instancias subsiguientes intentadas al primero. Una instancia comenzará a escuchar en un puerto predefinido si no encuentra una instancia que ya esté escuchando allí. Si ya existe una instancia, envía sus argumentos de línea de comando sobre el socket y sale.

código con explicación


Lo correcto es el bloqueo de aviso mediante flock(LOCK_EX) ; en Python, esto se encuentra en el módulo fcntl .

A diferencia de los archivos pidfiles, estos bloqueos siempre se liberan automáticamente cuando el proceso muere por cualquier motivo, no existen condiciones de carrera relacionadas con la eliminación de archivos (ya que el archivo no necesita ser eliminado para liberar el bloqueo), y no hay posibilidad de que sea diferente. proceso heredando el PID y apareciendo para validar un bloqueo obsoleto.

Si desea una detección de cierre no limpia, puede escribir un marcador (como su PID, para los tradicionalistas) en el archivo después de agarrar el bloqueo, y luego truncar el archivo al estado de 0 bytes antes de un apagado limpio (mientras se mantiene el bloqueo) ); por lo tanto, si no se mantiene el bloqueo y el archivo no está vacío, se indica un cierre no limpio.


Si crea un archivo de bloqueo y coloca el pid en él, puede verificar el ID de su proceso y decir si se colgó, ¿no?

No lo he hecho personalmente, así que tómelo con las cantidades adecuadas de sal. :pag


Solución de bloqueo completa utilizando el módulo fcntl :

import fcntl pid_file = ''program.pid'' fp = open(pid_file, ''w'') try: fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: # another instance is running sys.exit(1)


wxWidgets ofrece una clase wxSingleInstanceChecker para este propósito: wxPython doc o wxWidgets doc . El documento wxWidgets tiene código de muestra en C ++, pero el equivalente de python debería ser algo como esto (no probado):

name = "MyApp-%s" % wx.GetUserId() checker = wx.SingleInstanceChecker(name) if checker.IsAnotherRunning(): return False



Hay varias técnicas comunes que incluyen el uso de semáforos. El que veo más utilizado es crear un "archivo de bloqueo pid" en el inicio que contiene el pid del proceso en ejecución. Si el archivo ya existe cuando se inicia el programa, ábralo y agarre el pid dentro, verifique si se está ejecutando un proceso con ese pid, si es que comprueba el valor de la línea de comando en / proc / pid para ver si es un instancia de su programa, si se cierra, de lo contrario sobrescriba el archivo con su pid. El nombre habitual para el archivo pid es application_name .pid .