Estoy ampliando mis comentarios a una respuesta porque creo que algunos aspectos del problema específico se pasan por alto o se usan para sacar conclusiones erróneas.
En este punto, la pregunta de si se debe refactorizar es prematura (aunque probablemente se responderá con una forma específica de "sí").
El problema central aquí es que (como se señaló en algunas respuestas) los comentarios que cita indican claramente que el código tiene condiciones de carrera u otros problemas de concurrencia / sincronización, como se comentó aquí . Estos son problemas particularmente difíciles, por varias razones. En primer lugar, como ha descubierto, los cambios aparentemente no relacionados pueden desencadenar el problema (otros errores también pueden tener este efecto, pero los errores de concurrencia casi siempre lo hacen). En segundo lugar, son muy difíciles de diagnosticar: el error a menudo se manifiesta en un lugar que es distante en el tiempo o el código de la causa, y cualquier cosa que haga para diagnosticarlo puede hacer que desaparezca ( Heisenbugs ). En tercer lugar, los errores de concurrencia son muy difíciles de encontrar en las pruebas. En parte, esto se debe a la explosión combinatoria: es lo suficientemente malo para el código secuencial, pero agregar los posibles entrecruzamientos de la ejecución concurrente lo hace estallar hasta el punto en que el problema secuencial se vuelve insignificante en comparación. Además, incluso un buen caso de prueba solo puede desencadenar el problema ocasionalmente: Nancy Leveson calculó que uno de los errores letales en el Therac 25 ocurrió en 1 de aproximadamente 350 ejecuciones, pero si no sabe cuál es el error o si existe una, no sabe cuántas repeticiones hacen una prueba efectiva. Además, solo es posible realizar pruebas automáticas a esta escala, y es posible que el controlador de prueba imponga restricciones de tiempo sutiles, de modo que nunca vuelva a activar el error (Heisenbugs de nuevo).
Hay algunas herramientas para realizar pruebas de concurrencia en algunos entornos, como Helgrind para el código que usa POSIX pthreads , pero no conocemos los detalles aquí. Las pruebas deben complementarse con un análisis estático (¿o es al revés?), Si existen herramientas adecuadas para su entorno.
Para aumentar la dificultad, los compiladores (e incluso los procesadores, en tiempo de ejecución) a menudo tienen la libertad de reorganizar el código de manera que a veces hacen que el razonamiento sobre la seguridad de sus subprocesos sea muy poco intuitivo (quizás el caso más conocido es el idioma de bloqueo con doble control , aunque algunos entornos (Java, C ++ ...) se han modificado para mejorarlo. )
Este código puede tener un problema simple que está causando todos los síntomas, pero es más probable que tenga un problema sistémico que podría hacer que sus planes para agregar nuevas funciones se detengan. Espero haberlo convencido de que podría tener un problema grave en sus manos, posiblemente incluso una amenaza existencial para su producto, y lo primero que debe hacer es averiguar qué está sucediendo. Si esto revela problemas de concurrencia, le recomiendo encarecidamente que los solucione primero, antes incluso de preguntarse si debería hacer una refactorización más general, y antes de intentar agregar más funciones.