5

Estoy creando un algoritmo de recuperación de la memoria concurrente en C++. Periódicamente, las pilas de ejecución de los hilos del mutador deben inspeccionarse, de modo que pueda ver las referencias que están manteniendo actualmente los hilos. En el proceso de hacer esto, también necesito verificar los registros del hilo del mutador para verificar cualquier referencia que pueda estar ahí.¿Cómo detiene un hilo y vacía sus registros en la pila?

Es evidente que muchos # VM de JVM y C no tienen ningún problema en hacer esto como parte de su ciclo de recogida de basura. Sin embargo, no he podido encontrar una solución definitiva a este problema.

No puedo separar lo que está sucediendo en el recolector de basura de Bohem para inspeccionar el conjunto raíz, si puede (o saber cómo se hace), realmente me gustaría saber.

Idealmente podría provocar la interrupción del hilo del mutador y ejecutar un código de controlador que informara que es una PC y también eliminar cualquier referencia basada en registro en la pila, y luego quizás ayudar a terminar el ciclo de recolección . Creo que la mayoría de los compiladores en la mayoría de los sistemas eliminará automáticamente los registros de interrupciones o cuando la señal manejadores son llamados, pero no me queda claro en los detalles, o cómo acceder a esos datos. Parece que se pueden usar pilas separadas para controladores de interrupción y señal. Además, no puedo encontrar ninguna información sobre cómo orientar un tema en particular o cómo enviar una señal. Windows no parece ser compatible con esta forma de señalización de todos modos, y me gustaría que mi sistema se ejecute tanto en Linux como en Windows en los procesadores x86-64.

Edit: SuspendThread() se utiliza en algunas situaciones, aunque parece preferible utilizar safepoints. Alguna idea sobre por qué? ¿Hay alguna manera de lidiar con esperas de E/S duraderas u otras esperas para que vuelva el código del kernel?

+0

No se usa el enjuague, el colector simplemente verifica los registros para referencias de objetos. Fácil de hacer en Windows con GetThreadContext(). –

+0

Bueno, 'GetThreadContext' no lee los registros en absoluto. Lee la memoria en la que se guardaron los registros la última vez que un interruptor de contexto inactivó ese hilo en particular. –

+0

@coolkid: Los compiladores no descargan registros cuando ocurren interrupciones (ni emiten código para hacerlo), eso es una característica de la CPU. –

Respuesta

3

pensé que esto era una pregunta muy interesante, así que cavó en ella un poco. Resulta que el Hotspot JVM utiliza un mecanismo llamado "safepoints" que causan los hilos de la JVM para cooperativamente todo pararse para que el GC puede comenzar. En otras palabras, el hilo que inicia el GC no detiene por la fuerza los otros hilos, los otros hilos se suspenden voluntariamente por varios mecanismos inteligentes.

no creo que la JVM escanea registros, porque un punto seguro se define de tal manera que todas las raíces son conocidos (supongo que esto significa en la memoria).

Para más información ver:

En lo que respecta a su deseo de "interrumpir" todos los hilos, según la plataforma de diapositivas I mencionado anteriormente, la suspensión del hilo "no es confiable en Solaris y Linux, por ejemplo, señales espurias". No estoy seguro de qué mecanismo existe para la suspensión de hilo a la que se referirán las diapositivas.

+0

Hmm .. Si este es el caso, ¿cómo lidiar con el hecho de que un hilo podría no programarse por algún tiempo si está esperando IO o el sistema operativo simplemente tiene muchos procesos en competencia? Odiaría tener que parar por eso. – coolkid

+0

Si revisa el enlace a safepoint.cpp anterior, los comentarios indican que los hilos actualmente bloqueados no podrán continuar hasta que se complete la operación de safepoint (por lo que es como si ya estuvieran en un punto seguro). Supongo que todos los hilos ejecutables deben programarse antes de que pueda comenzar el GC para que puedan pausar en un estado conocido, probablemente de ninguna manera. –

+0

¡Yikes! Eso podría demorar mucho si uno de ellos está esperando IO o está esperando a que se libere un bloqueo. Alguien sabe con certeza si este es realmente el caso? – coolkid

1

En Windows, debe poder hacer esto usando SuspendThread (y ResumeThread) junto con GetThreadContext (como mencionó Hans). Todas estas funciones toman identificadores para el subproceso específico al que pretende dirigirse.

Para obtener una lista de todos los hilos en el proceso actual, consulte this (toolhlp32 funciona en x64, a pesar de su mal esquema de nombres ...).

Como punto de interés, una forma de descargar los registros a la pila en x86 es utilizar las instrucciones de ensamblaje PUSHAD.

+0

La forma "habitual" de enjuagar los registros en la pila es mediante interrupción. –

+0

@BenVoigt: afaiak windows no proporciona eso fuera del modo kernel (podría estar equivocado). – Necrolis

+0

Esa es la forma tradicional de acceder a los servicios del kernel desde el modo de usuario, es con una interrupción de software. x86 ahora tiene la instrucción 'sysenter', que optimiza las cosas un poco, pero creo que todavía realiza el mismo ahorro de registro. Pero realmente, solo estaba comentando tu declaración de que 'PUSHAD' es la única forma de guardar registros en la pila, ya que no lo es. Por cierto, los interruptores de contexto son causados ​​por interrupciones (E/S o temporizador) y así es como el estado del hilo termina en la memoria para que GetThreadContext pueda acceder. –

Cuestiones relacionadas