Recientemente, me han hecho una pregunta en una entrevista cuál es la diferencia entre un proceso y un hilo. Realmente, no sabía la respuesta. Pensé por un minuto y di una respuesta muy extraña.
Los hilos comparten la misma memoria, los procesos no. Después de responder esto, el entrevistador me dio una sonrisa malvada y me lanzó las siguientes preguntas:
P. ¿Conoces los segmentos en los que se divide un programa?
Mi respuesta: sí (pensé que era fácil) Pila, datos, código, montón
P. Entonces, dime: ¿qué segmentos comparten los hilos?
No pude responder a esto y terminé diciendo todas.
Por favor, ¿alguien puede presentar las respuestas correctas e impresionantes para la diferencia entre un proceso y un hilo?
Respuestas:
Estás bastante correcto, pero los hilos comparten todos los segmentos excepto la pila. Los subprocesos tienen pilas de llamadas independientes, sin embargo, la memoria en otras pilas de subprocesos todavía es accesible y, en teoría, podría mantener un puntero a la memoria en el marco de pila local de otro subproceso (¡aunque probablemente debería encontrar un lugar mejor para colocar esa memoria!).
fuente
De Wikipedia (creo que sería una buena respuesta para el entrevistador: P)
fuente
Algo que realmente debe señalarse es que realmente hay dos aspectos en esta pregunta: el aspecto teórico y el aspecto de las implementaciones.
Primero, veamos el aspecto teórico. Debe comprender qué es un proceso conceptualmente para comprender la diferencia entre un proceso y un hilo y lo que se comparte entre ellos.
Tenemos lo siguiente de la sección 2.2.2 El modelo de hilo clásico en los sistemas operativos modernos 3e de Tanenbaum:
Él continúa:
Más abajo proporciona la siguiente tabla:
Lo anterior es lo que necesita para que los hilos funcionen. Como otros han señalado, cosas como los segmentos son detalles de implementación dependientes del sistema operativo.
fuente
Dígale al entrevistador que depende completamente de la implementación del sistema operativo.
Tome Windows x86 por ejemplo. Solo hay 2 segmentos [1], Código y Datos. Y ambos están asignados a todo el espacio de direcciones de 2GB (lineal, usuario). Base = 0, Límite = 2GB. Habrían hecho uno, pero x86 no permite que un segmento sea tanto de lectura / escritura como de ejecución. Entonces hicieron dos, y configuraron CS para que apunte al descriptor de código, y el resto (DS, ES, SS, etc.) para apuntar al otro [2]. ¡Pero ambos apuntan a lo mismo!
La persona que lo entrevistó hizo una suposición oculta de que él / ella no declaró, y ese es un truco estúpido para hacer.
Entonces con respecto
Los segmentos son irrelevantes para la pregunta, al menos en Windows. Los hilos comparten todo el espacio de direcciones. Solo hay 1 segmento de pila, SS, y apunta exactamente a las mismas cosas que DS, ES y CS hacen [2]. Es decir, todo el sangriento espacio de usuario . 0-2GB. Por supuesto, eso no significa que los hilos solo tengan 1 pila. Naturalmente, cada uno tiene su propia pila, pero los segmentos x86 no se utilizan para este propósito.
Quizás * nix hace algo diferente. Quién sabe. La premisa en la que se basaba la pregunta estaba rota.
ntsd notepad
:cs=001b ss=0023 ds=0023 es=0023
fuente
En general, los hilos se denominan proceso de peso ligero. Si dividimos la memoria en tres secciones, será: Código, datos y Pila. Cada proceso tiene su propio código, datos y secciones de pila y, debido a este cambio de contexto, el tiempo es un poco alto. Para reducir el tiempo de cambio de contexto, las personas han ideado el concepto de subproceso, que comparte segmento de datos y código con otro subproceso / proceso y tiene su propio segmento STACK.
fuente
Un proceso tiene segmentos de código, datos, montón y pila. Ahora, el puntero de instrucción (IP) de un hilo O hilos apunta al segmento de código del proceso. Los segmentos de datos y montón son compartidos por todos los hilos. ¿Qué pasa con el área de la pila? ¿Cuál es realmente el área de la pila? Es un área creada por el proceso solo para que lo use su hilo ... porque las pilas se pueden usar de una manera mucho más rápida que los montones, etc. El área de pila del proceso se divide entre hilos, es decir, si hay 3 hilos, entonces el El área de apilamiento del proceso se divide en 3 partes y cada una se da a los 3 hilos. En otras palabras, cuando decimos que cada hilo tiene su propia pila, esa pila es en realidad una parte del área de pila de proceso asignada a cada hilo. Cuando un subproceso finaliza su ejecución, el proceso recupera la pila del subproceso. De hecho, no solo la pila de un proceso está dividida entre hilos, sino que todo el conjunto de registros que usa un hilo como SP, PC y registros de estado son los registros del proceso. Entonces, cuando se trata de compartir, el código, los datos y las áreas de almacenamiento dinámico se comparten, mientras que el área de la pila se divide entre hilos.
fuente
Los subprocesos comparten el código y los segmentos de datos y el montón, pero no comparten la pila.
fuente
Los hilos comparten datos y código mientras que los procesos no. La pila no se comparte para ambos.
Los procesos también pueden compartir memoria, más precisamente código, por ejemplo después de un
Fork()
, pero esto es un detalle de implementación y optimización (del sistema operativo). El código compartido por múltiples procesos se duplicará (con suerte) en la primera escritura en el código, esto se conoce como copia en escritura . No estoy seguro de la semántica exacta para el código de subprocesos, pero supongo que el código compartido.1 El código es lógicamente privado, pero podría compartirse por razones de rendimiento. 2 No estoy 100% seguro.
fuente
Los hilos comparten todo [1]. Hay un espacio de direcciones para todo el proceso.
Cada hilo tiene su propia pila y registros, pero todas las pilas de hilos son visibles en el espacio de direcciones compartido.
Si un subproceso asigna algún objeto en su pila y envía la dirección a otro subproceso, ambos tendrán igual acceso a ese objeto.
En realidad, acabo de notar un problema más amplio: creo que estás confundiendo dos usos del segmento de palabras .
El formato de archivo para un ejecutable (p. Ej., ELF) tiene distintas secciones, que pueden denominarse segmentos, que contienen código compilado (texto), datos inicializados, símbolos de enlace, información de depuración, etc. No hay segmentos de montón o pila. aquí, ya que esas son construcciones de tiempo de ejecución solamente.
Estos segmentos de archivo binario se pueden asignar al espacio de direcciones del proceso por separado, con diferentes permisos (por ejemplo, ejecutable de solo lectura para código / texto, y no ejecutable de copia en escritura para datos inicializados).
Las áreas de este espacio de direcciones se usan para diferentes propósitos, como la asignación del montón y las pilas de subprocesos, por convención (aplicada por las bibliotecas de tiempo de ejecución de idioma). Sin embargo, todo es solo memoria, y probablemente no esté segmentado a menos que esté ejecutando en modo virtual 8086. La pila de cada subproceso es una porción de memoria asignada en el momento de la creación del subproceso, con la dirección superior de la pila actual almacenada en un registro de puntero de la pila, y cada subproceso mantiene su propio puntero de la pila junto con sus otros registros.
[1] OK, lo sé: máscaras de señal, TSS / TSD, etc. Sin embargo, el espacio de direcciones, incluidos todos sus segmentos de programa asignados, aún se comparten.
fuente
En un marco x86, uno puede dividir tantos segmentos (hasta 2 ^ 16-1). Las directivas ASM SEGMENT / ENDS permiten esto, y los operadores SEG y OFFSET permiten la inicialización de registros de segmento. CS: IP suele ser inicializado por el cargador, pero para DS, ES, SS, la aplicación es responsable de la inicialización. Muchos entornos permiten las llamadas "definiciones de segmento simplificadas" como .code, .data, .bss, .stack, etc. y, dependiendo también del "modelo de memoria" (pequeño, grande, compacto, etc.) el cargador inicializa registros de segmento en consecuencia. Por lo general, .data, .bss, .stack y otros segmentos habituales (no he hecho esto desde hace 20 años, así que no recuerdo todos) se agrupan en un solo grupo, es por eso que generalmente DS, ES y SS apuntan a misma área, pero esto es solo para simplificar las cosas.
En general, todos los registros de segmento pueden tener valores diferentes en tiempo de ejecución. Entonces, la pregunta de la entrevista fue correcta: cuál de los CÓDIGOS, DATOS y PILAS se comparten entre los hilos. La gestión del montón es otra cosa: es simplemente una secuencia de llamadas al sistema operativo. Pero, ¿qué pasa si no tiene un sistema operativo en absoluto, como en un sistema integrado? ¿Puede tener nuevo / eliminar en su código?
Mi consejo para los jóvenes: lea un buen libro de programación de ensamblajes. Parece que los planes de estudio universitarios son bastante pobres a este respecto.
fuente
Extracto de: La interfaz de programación de Linux: Manual de programación del sistema Linux y UNIX, Michael Kerrisk , página 619
fuente
El subproceso comparte el montón (hay una investigación sobre el montón específico del subproceso) pero la implementación actual comparte el montón. (y por supuesto el código)
fuente
En proceso, todos los subprocesos comparten recursos del sistema, como memoria de almacenamiento dinámico, etc., mientras que Thread tiene su propia pila
Por lo tanto, su ans debe ser memoria de montón que todos los hilos comparten para un proceso.
fuente