¿Los subprocesos tienen un montón distinto?

114

Hasta donde yo sé, cada hilo obtiene una pila distinta cuando el hilo es creado por el sistema operativo. Me pregunto si cada hilo tiene un montón distinto a sí mismo también.

Martín Thoma
fuente
sí, windows y linux, biblioteca c
3
Agradable. +1 sigue viniendo esas preguntas fundamentales.

Respuestas:

128

No. Todos los subprocesos comparten un montón común.

Cada hilo tiene una pila privada , a la que puede agregar y quitar elementos rápidamente. Esto hace que la memoria basada en pila sea rápida, pero si usa demasiada memoria de pila, como ocurre en la recursividad infinita, obtendrá un desbordamiento de pila.

Dado que todos los subprocesos comparten el mismo montón, el acceso al asignador / desasignador debe sincronizarse. Existen varios métodos y bibliotecas para evitar la contención de asignadores .

Algunos lenguajes le permiten crear grupos privados de memoria, o montones individuales, que puede asignar a un solo hilo.

Brianegge
fuente
5
Por lo general, los subprocesos comparten recursos, como la memoria, por lo que cualquier implementación de subprocesos que no sea cerebral compartiría el montón.
R. Martinho Fernandes
10
La razón principal por la que cada hilo tiene su propia pila es para que el hilo realmente pueda hacer algo (como llamar a funciones) ...
Edmund
3
Cada hilo tiene una pila separada, pero no es necesariamente 'privada'. Por lo general, otros subprocesos pueden acceder a él.
zch
you will get a stack overflow.¡Un desbordamiento de pila en Stack Overflow!
John Strood
2
@crisron Es posible configurar un montón separado para cada hilo, pero si lo hace en lugar de usar el montón compartido predeterminado, entonces se vuelve difícil para, por ejemplo, el hilo A asignar un búfer, llenarlo con datos, pasarlo al hilo B , y hacer que el hilo B use los datos y luego libere el búfer (porque el subproceso B no tiene acceso al montón del subproceso A, el subproceso B no puede liberar el búfer; lo mejor que podría hacer el subproceso B es devolver el búfer al subproceso A de nuevo y hacer que el hilo A lo libere).
Jeremy Friesner
9

De forma predeterminada, C solo tiene un montón.

Dicho esto, algunos asignadores que son conscientes de los subprocesos dividirán el montón para que cada subproceso tenga su propia área para realizar la asignación. La idea es que esto debería mejorar la escala del montón.

Un ejemplo de tal montón es Hoard .

R Samuel Klatchko
fuente
De forma predeterminada, C y C ++ no tienen varios subprocesos. La especificación 2003 c ++ al menos no tiene en cuenta los subprocesos en el diseño de su máquina virtual, por lo que los subprocesos, en c ++, se definen por implementación.
Chris Becke
Incluso si diferentes subprocesos tienen diferentes áreas para asignar en el montón, aún pueden ver los datos asignados por otro subproceso, por lo que los subprocesos aún comparten el mismo montón.
Ken Bloom
1
Actualización: a partir de C ++ 11, los hilos ya no están definidos por la implementación.
Michael Dorst
5

Depende del sistema operativo. El tiempo de ejecución estándar de c en Windows y Unices usa un montón compartido entre subprocesos. Esto significa bloquear todos los archivos malloc / free.

En Symbian, por ejemplo, cada subproceso viene con su propio montón, aunque los subprocesos pueden compartir punteros a los datos asignados en cualquier montón. En mi opinión, el diseño de Symbian es mejor ya que no solo elimina la necesidad de bloquear durante la asignación / libre, sino que también fomenta la especificación limpia de la propiedad de los datos entre los subprocesos. Además, en ese caso, cuando un hilo muere, toma todos los objetos que asignó junto con él, es decir, no puede filtrar los objetos que ha asignado, que es una propiedad importante en los dispositivos móviles con memoria limitada.

Erlang también sigue un diseño similar en el que un "proceso" actúa como una unidad de recolección de basura. Todos los datos se comunican entre procesos mediante copia, excepto los blobs binarios que se cuentan por referencia (creo).

Srikumar
fuente
3

Cada hilo tiene su propia pila y pila de llamadas.

Cada hilo comparte el mismo montón.

tsalter
fuente
3

Depende de a qué te refieres exactamente cuando dices "montón".

Todos los subprocesos comparten el espacio de direcciones, por lo que los objetos asignados al montón son accesibles desde todos los subprocesos. Técnicamente, las pilas también se comparten en este sentido, es decir, nada le impide acceder a la pila de otros hilos (aunque casi nunca tendría sentido hacerlo).

Por otro lado, existen estructuras de montón que se utilizan para asignar memoria. Ahí es donde se realiza toda la contabilidad para la asignación de memoria del montón. Estas estructuras están organizadas de manera sofisticada para minimizar la contención entre los subprocesos, por lo que algunos subprocesos pueden compartir una estructura de montón (una arena) y algunos pueden usar arenas distintas.
Consulte el siguiente hilo para obtener una excelente explicación de los detalles: ¿Cómo funciona malloc en un entorno multiproceso?

VladV
fuente
1

Normalmente, los subprocesos comparten el montón y otros recursos, sin embargo, hay construcciones similares a subprocesos que no lo hacen. Entre estas construcciones tipo hilo se encuentran los procesos ligeros de Erlang y los procesos completos de UNIX (creados con una llamada a fork()). Es posible que también esté trabajando en la simultaneidad de varias máquinas, en cuyo caso sus opciones de comunicación entre subprocesos son considerablemente más limitadas.

Ken Bloom
fuente
Pensé que la bifurcación era más como crear un nuevo proceso que simplemente copiaba los datos en una nueva ubicación de memoria.
Jason Tholstrup
2
fork () puede servir en muchos casos de uso donde también se pueden usar hilos. Debido al copy-on-write, no hay una diferencia de costo significativa en los sistemas Unix. El caso de uso típico es donde el trabajador es autónomo (como un servidor web) del resto del servicio. Otra posibilidad es comunicarse a través de stdin / out con el hilo / programa principal. fork () es fuerte en Unix, mientras que otras plataformas como Windows prefieren los subprocesos. La razón principal probablemente sea que usar fork () es mucho más simple y seguro y Unix tiene esta filosofía de simplicidad. Vea, por ejemplo, el servidor web apache, con su lenta transición a subprocesos.
ypnos
1

En términos generales, todos los subprocesos utilizan el mismo espacio de direcciones y, por lo tanto, suelen tener un solo montón.

Sin embargo, puede resultar un poco más complicado. Es posible que esté buscando Thread Local Storage (TLS), pero solo almacena valores individuales.

Específico de Windows: el espacio TLS se puede asignar usando TlsAlloc y liberarse usando TlsFree (descripción general aquí ). De nuevo, no es un montón, solo DWORD.

Curiosamente, Windows admite varios montones por proceso. Se puede almacenar el identificador de Heap en TLS. Entonces tendrías algo como un "Montón local de subprocesos". Sin embargo, solo el identificador no es conocido por los otros subprocesos, aún pueden acceder a su memoria usando punteros, ya que sigue siendo el mismo espacio de direcciones.

EDITAR : Algunos asignadores de memoria (específicamente jemalloc en FreeBSD) usan TLS para asignar "arenas" a los hilos. Esto se hace para optimizar la asignación de múltiples núcleos al reducir la sobrecarga de sincronización.

Meinersbur
fuente
> "Curiosamente, Windows admite varios montones por proceso.", No es extraño en absoluto, uno podría usar diferentes montones para diferentes tipos de asignaciones, solo agrega más flexibilidad. Por supuesto, siempre puede utilizar VirtualAlloc y crear su propio montón como quiera.
1

En el sistema operativo FreeRTOS, las tareas (subprocesos) comparten el mismo montón, pero cada una de ellas tiene su propia pila. Esto es muy útil cuando se trata de arquitecturas de bajo consumo de RAM, porque varios subprocesos pueden acceder / compartir el mismo grupo de memoria, pero esto viene con una pequeña trampa, el desarrollador debe tener en cuenta que un mecanismo para sincronizar malloc y se necesita libre, por eso es necesario utilizar algún tipo de sincronización / bloqueo de proceso al asignar o liberar memoria en el montón, por ejemplo un semáforo o un mutex.

Noreddine -Kessa
fuente