2009-07-24 25 views
7

Mi situación: un servidor y algunos clientes (aunque no muchos). El servidor solo puede responder a un cliente a la vez, por lo que debe estar en cola. Estoy usando un mutex (boost::interprocess::interprocess_mutex) para hacer esto, envuelto en un boost::interprocess::scoped_lock.¿Cómo puedo tomar posesión de un boost abandonado :: interprocess :: interprocess_mutex?

El problema es que si un cliente muere inesperadamente (es decir, no se ejecuta ningún destructor) mientras mantiene el mutex, los otros clientes tienen problemas porque están esperando ese mutex. He considerado utilizar la espera temporizada, así que si el cliente espera, digamos, 20 segundos y no obtiene el mutex, sigue adelante y habla con el servidor de todos modos.

Problemas con este enfoque: 1) lo hace cada vez. Si está en un bucle, hablando constantemente con el servidor, necesita esperar el tiempo de espera cada vez. 2) Si hay tres clientes, y uno de ellos muere mientras mantiene el mutex, los otros dos esperarán 20 segundos y hablarán con el servidor al mismo tiempo, exactamente lo que estaba tratando de evitar.

Entonces, ¿cómo puedo decir a un cliente, "oye allí, parece que este mutex ha sido abandonado, tomar posesión de él"?

+2

Si confía en los clientes para hacer la sincronización, lo está haciendo hacia atrás. Realmente debería arreglar su servidor para que pueda aceptar conexiones múltiples, incluso si solo hace que las otras conexiones esperen mientras sirve una a la vez. Eso le permite sacar la parte * interprocess * de la ecuación. –

+0

Punto justo. Sin embargo, mi aplicación se especificó originalmente como teniendo solo un cliente a la vez. Recientemente (como en la actualidad) descubrí que podría haber varios clientes. Intenté resolverlo de la manera fácil, pero supongo que tendré que encontrar algo más sofisticado. –

+0

Parece que todo el mecanismo de mutex está defectuoso sin un mecanismo de recuperación. Wish boost corrige esto. – balki

Respuesta

6

Desafortunadamente, esto no es compatible con la API boost :: interprocess as-is. Hay algunas maneras que usted podría ponerla en práctica sin embargo:

Si se encuentra en una plataforma POSIX con soporte para pthread_mutexattr_setrobust_np, editar realce/entre procesos/sincronización/POSIX/thread_helpers.hpp y aumentar/entre procesos/sincronización/POSIX/interprocess_mutex. hpp para usar mutexes robustos, y para manejar de alguna manera el retorno EOWNERDEAD de pthread_mutex_lock.

Si está en alguna otra plataforma, puede editar boost/interprocess/sync/emulation/interprocess_mutex.hpp para usar un contador de generación, con el indicador bloqueado en el bit inferior. Luego puede crear un protocolo de reclamación que establecerá un indicador en la palabra de bloqueo para indicar un reclamo pendiente, luego haga un compare-and-swap después de un tiempo de espera para verificar que la misma generación aún esté en la palabra de bloqueo, y si es así reemplace con un valor bloqueado de próxima generación.

Si está en Windows, otra buena opción sería usar objetos mutex nativos; es probable que sean más eficientes que ocupados, esperando de todos modos.

Es posible que también desee reconsiderar el uso de un protocolo de memoria compartida; ¿por qué no utilizar un protocolo de red?

+0

Gran respuesta. No obstante, no creo que lo implemente; no parece valer la pena, pensaré en otra cosa. Acerca de su sugerencia de usar un protocolo de red, no podría estar más de acuerdo con usted. Lamentablemente, es demasiado tarde en el juego para cambiar las cosas de manera tan radical. –

Cuestiones relacionadas