Un problema frecuente es cómo impedir que un programa se ejecute dos o más veces de forma concurrente. Uno de los mecanismos más utilizados para afrontar este problema es el conocido como file locking. En un proyecto hemos utilizado D-Bus para implementar un mecanismo similar.

D-Bus es un sistema de bus de mensajes, una forma sencilla para que las aplicaciones se comuniquen entre sí. De forma muy resumida (más información en la web del proyecto D-Bus), cuando un usuario inicia una sesión gráfica en el sistema tiene a su disposición un bus del sistema y un bus del usuario ligado a su sesión. Un programa en ejecución se puede registrar en uno de estos buses para ofrecer uno o más servicios, identificados unívocamente con un identificador asignado por D-Bus (p.e. :34-907) y un nombre conocido elegido por el programa (p.e. es.foo.Bar).

Puesto que sólo puede haber un único servicio en un bus con el mismo nombre, es sencillo idear un mecanismo de control de concurrencia. Consistiría básicamente en consultar si existe un servicio en el bus de sesión con un determinado nombre. Un ejemplo sencillo implementado en Python es el siguiente:

#!/usr/bin/env python
# dbus-singleton-example.py

import sys
import gobject
import dbus
import dbus.mainloop.glib
import dbus.service

BUS_NAME = 'es.foo.Bar'

class DBusSingleton(dbus.service.Object):
    def __init__(self):
        bus = dbus.SessionBus()
        if not bus.name_has_owner(BUS_NAME):
            bus.request_name(BUS_NAME)
            dbus.service.Object.__init__(self, bus, '/es/foo/bar')
            print 'Adquired D-Bus name: "%s"' % BUS_NAME
        else:
            print 'Failed to request D-Bus name: "%s"' % BUS_NAME
            sys.exit()

if __name__ == '__main__':
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    singleton = DBusSingleton()

    loop = gobject.MainLoop()
    loop.run()

Al ejecutarlo de forma concurrente n veces se obtiene la salida:

$ for i in {1..5}; do python dbus-concurrenty-example.py & done
Adquired D-Bus name: "es.foo.Bar"
Failed to request D-Bus name: "es.foo.Bar"
Failed to request D-Bus name: "es.foo.Bar"
Failed to request D-Bus name: "es.foo.Bar"
Failed to request D-Bus name: "es.foo.Bar"


Comments

comments powered by Disqus