¿Cómo bloquear la ejecución de dos instancias del mismo progtwig?

Necesito asegurarme de que el usuario pueda ejecutar solo una instancia de mi progtwig a la vez.
Lo que significa que tengo que comprobar programáticamente si el mismo progtwig ya se está ejecutando y lo dejo en ese caso.

Lo primero que me vino a la mente fue crear un archivo en algún lugar, cuando el progtwig comienza. Luego, cada otra instancia del progtwig verificará este archivo y saldrá si lo encontró.
El problema es que el progtwig siempre debe salir con elegancia y poder eliminar el archivo que creó para que funcione. En caso de, por ejemplo, un corte de energía, el archivo de locking permanece en su lugar y el progtwig no se puede iniciar de nuevo.

Para resolver esto, decidí almacenar el ID del proceso del primer progtwig en el archivo de locking y cuando se inicia otra instancia, comprueba si el PID del archivo está conectado a algún proceso en ejecución.
Si el archivo no existe, está vacío o el PID no corresponde a ningún proceso existente, el progtwig continúa ejecutándose y escribe su propio PID en el archivo.

Esto parece funcionar bastante bien: incluso después de un cierre inesperado, la posibilidad de que el ID del proceso (ahora obsoleto) se asocie con algún otro progtwig, parece ser bastante bajo.

Pero todavía no se siente bien (existe la posibilidad de que un proceso no relacionado lo bloquee) y trabajar con ID de procesos parece ir más allá del C ++ estándar y probablemente tampoco sea muy portátil.

Entonces, ¿hay otra forma (más limpia y segura) de hacer esto? Idealmente, debería funcionar con el estándar ISO 98 C ++ y con Windows y * nix por igual.
Si no se puede hacer de plataforma independiente, Linux / Unix es una prioridad para mí.

Existen varios métodos que puede usar para lograr solo una instancia de su aplicación:

Método 1: objeto o memoria de sincronización global

Por lo general, se realiza creando un mutex o evento global con nombre. Si ya está creado, sabrá que el progtwig ya se está ejecutando.

Por ejemplo, en Windows puedes hacer:

#define APPLICATION_INSTANCE_MUTEX_NAME "{BA49C45E-B29A-4359-A07C-51B65B5571AD}" //Make sure at most one instance of the tool is running HANDLE hMutexOneInstance(::CreateMutex( NULL, TRUE, APPLICATION_INSTANCE_MUTEX_NAME)); bool bAlreadyRunning((::GetLastError() == ERROR_ALREADY_EXISTS)); if (hMutexOneInstance == NULL || bAlreadyRunning) { if(hMutexOneInstance) { ::ReleaseMutex(hMutexOneInstance); ::CloseHandle(hMutexOneInstance); } throw std::exception("The application is already running"); } 

Método 2: Bloqueando un archivo, el segundo progtwig no puede abrir el archivo, por lo que está abierto

También podría abrir un archivo exclusivamente al bloquearlo en la aplicación abierta. Si el archivo ya está abierto exclusivamente y su aplicación no puede recibir un identificador de archivo, significa que el progtwig ya se está ejecutando. En Windows, simplemente no debe especificar los indicadores de uso compartido FILE_SHARE_WRITE en el archivo que está abriendo con CreateFile API. En Linux usarías flock .

Método 3: Buscar el nombre del proceso:

Puede enumerar los procesos activos y buscar uno con su nombre de proceso.

Su método para escribir el proceso pid en un archivo es común y se usa en muchas aplicaciones establecidas diferentes. De hecho, si busca en su directorio /var/run este momento, apuesto a que ya encontrará varios archivos *.pid .

Como dices, no es 100% robusto porque existe la posibilidad de que los pids se confundan. He oído hablar de progtwigs que usan flock() para bloquear un archivo específico de la aplicación que el sistema operativo desbloqueará automáticamente cuando el proceso finalice, pero este método es más específico de la plataforma y menos transparente.

Tenga cuidado, un progtwig de instancia única es su propia denegación de servicio .

El enlace describe el problema de seguridad de la detección de instancia única y sugiere utilizar un método asegurable para que al menos los procesos de derechos inferiores no puedan explotar el problema.

Es muy poco común prohibir que se ejecuten varias instancias de un progtwig.

Si el progtwig es, por ejemplo, un daemon de red, no es necesario que prohíba activamente varias instancias, solo la primera instancia escuchará el socket, por lo que las instancias posteriores se apagarán automáticamente. Si se trata, por ejemplo, de un RDBMS, no es necesario que prohíba activamente varias instancias; solo la primera instancia puede abrir y bloquear los archivos. etc.

De hecho, uso exactamente el proceso que describes, y funciona bien, excepto en el caso extremo que ocurre cuando de repente te quedas sin espacio en el disco y ya no puedes crear archivos.

La forma “correcta” de hacer esto es probablemente usar la memoria compartida: http://www.cs.cf.ac.uk/Dave/C/node27.html

Si quieres algo que sea pantano estándar, entonces usar un archivo como ‘locking’ es más o menos el camino a seguir. Tiene el inconveniente que usted mencionó (si su aplicación no se limpia, reiniciar puede ser un problema).

Este método es utilizado por bastantes aplicaciones, pero el único que puedo recordar en la cima de mi cabeza es VMware. Y sí, hay momentos en los que tienes que entrar y eliminar el ‘* .lck’ cuando las cosas se bloquean.

Usar un mutex global u otro objeto de sistema como lo menciona Brian Bondy es una mejor forma de hacerlo, pero estos son específicos de la plataforma (a menos que use alguna otra biblioteca para abstraer los detalles de la plataforma).

No tengo una buena solución, pero dos pensamientos:

  1. Puede agregar una capacidad de ping para consultar el otro proceso y asegurarse de que no sea un proceso no relacionado. Firefox hace algo similar en Linux y no inicia una nueva instancia cuando ya se está ejecutando.

  2. Si usa un manejador de señal, puede asegurarse de que el archivo pid se elimine en todos menos en kill -9

Escalo la lista de procesos buscando el nombre de mis aplicaciones ejecutables con los parámetros correspondientes de la línea de comando y luego salgo si hay una coincidencia.

Mi aplicación puede ejecutarse más de una vez, pero no quiero que ejecute el mismo archivo de configuración al mismo tiempo.

Obviamente, esto es específico de Windows, pero el mismo concepto es bastante fácil en cualquier sistema * NIX, incluso sin bibliotecas específicas simplemente abriendo el comando de shell ‘ps -ef’ o una variación y buscando su aplicación.

  '************************************************************************* ' Sub: CheckForProcess() ' Author: Ron Savage ' Date: 10/31/2007 ' ' This routine checks for a running process of this app with the same ' command line parameters. '************************************************************************* Private Function CheckForProcess(ByVal processText As String) As Boolean Dim isRunning As Boolean = False Dim search As New ManagementObjectSearcher("SELECT * FROM Win32_process") Dim info As ManagementObject Dim procName As String = "" Dim procId As String = "" Dim procCommandLine As String = "" For Each info In search.Get() If (IsNothing(info.Properties("Name").Value)) Then procName = "NULL" Else procName = Split(info.Properties("Name").Value.ToString, ".")(0) If (IsNothing(info.Properties("ProcessId").Value)) Then procId = "NULL" Else procId = info.Properties("ProcessId").Value.ToString If (IsNothing(info.Properties("CommandLine").Value)) Then procCommandLine = "NULL" Else procCommandLine = info.Properties("CommandLine").Value.ToString If (Not procId.Equals(Me.processId) And procName.Equals(processName) And procCommandLine.Contains(processText)) Then isRunning = True End If Next Return (isRunning) End Function 

Encontré una forma de plataforma cruzada para hacer esto usando boost/interprocess/sync/named_mutex . Por favor, consulte esta respuesta https://stackoverflow.com/a/42882353/4806882