¿Qué recursos se comparten entre hilos?

Recientemente, me preguntaron 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 contestar esto, el entrevistador me dirigió una sonrisa maligna y me lanzó las siguientes preguntas:

P. ¿Conoces los segmentos en los que se divide un progtwig?

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é diciéndolos a todos.

Por favor, ¿alguien puede presentar las respuestas correctas e impresionantes para la diferencia entre un proceso y un hilo?

    Estás bastante correcto, pero los hilos comparten todos los segmentos excepto la stack. Los subprocesos tienen stacks de llamadas independientes, sin embargo, la memoria en otras stacks de subprocesos aún está accesible y, en teoría, puede mantener un puntero a la memoria en el marco de stack local de otro subproceso (aunque probablemente debería encontrar un lugar mejor para guardar esa memoria).

    De Wikipedia (creo que sería una muy buena respuesta para el entrevistador: P)

    Los hilos difieren de los procesos tradicionales del sistema operativo multitarea en que:

    • los procesos son típicamente independientes, mientras que los hilos existen como subconjuntos de un proceso
    • los procesos llevan información de estado considerable, mientras que los hilos múltiples dentro de un proceso comparten estado, memoria y otros recursos
    • los procesos tienen espacios de direcciones separados, mientras que los hilos comparten su espacio de direcciones
    • los procesos interactúan solo a través de mecanismos de comunicación interproceso provistos por el sistema.
    • El cambio de contexto entre hilos en el mismo proceso suele ser más rápido que el cambio de contexto entre procesos.

    Algo que realmente debe señalarse es que en realidad hay dos aspectos en esta pregunta: el aspecto teórico y el aspecto de las implementaciones.

    Primero, veamos el aspecto teórico. Debe entender qué es conceptualmente un proceso para comprender la diferencia entre un proceso y un hilo y qué se comparte entre ellos.

    Tenemos lo siguiente de la sección 2.2.2 El modelo de subprocesamiento clásico en sistemas operativos modernos 3e por Tanenbaum:

    El modelo de proceso se basa en dos conceptos independientes: agrupación y ejecución de recursos. Algunas veces es útil separarlos; aquí es donde entran los hilos …

    Él continúa:

    Una forma de ver un proceso es que es una forma de agrupar los recursos relacionados. Un proceso tiene un espacio de direcciones que contiene texto de progtwig y datos, así como otros recursos. Estos recursos pueden incluir archivos abiertos, procesos secundarios, alarmas pendientes, manejadores de señal, información de contabilidad y más. Al juntarlos en forma de proceso, se pueden administrar más fácilmente. El otro concepto que tiene un proceso es un hilo de ejecución, por lo general abreviado a solo hilo. El hilo tiene un contador de progtwig que realiza un seguimiento de qué instrucción ejecutar a continuación. Tiene registros, que contienen sus variables de trabajo actuales. Tiene una stack, que contiene el historial de ejecución, con un cuadro para cada procedimiento llamado pero del que aún no se ha devuelto. Aunque un hilo debe ejecutarse en algún proceso, el hilo y su proceso son conceptos diferentes y pueden tratarse por separado. Los procesos se usan para agrupar recursos; los hilos son las entidades progtwigdas para la ejecución en la CPU.

    Más abajo, proporciona la siguiente tabla:

    Per process items | Per thread items ------------------------------|----------------- Address space | Program counter Global variables | Registers Open files | Stack Child processes | State Pending alarms | Signals and signal handlers | Accounting information | 

    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.

    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 se asignan a todo el espacio de direcciones de 2 GB (lineal, de usuario). Base = 0, Límite = 2GB. Habrían creado uno pero x86 no permite que un segmento sea tanto de lectura como de escritura y ejecución. Entonces hicieron dos y configuraron CS para apuntar al descriptor de código y el rest (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 de sacar.

    Entonces con respecto a

    Q. Entonces dime qué segmento de hilo comparte?

    Los segmentos son irrelevantes para la pregunta, al menos en Windows. Los subprocesos comparten todo el espacio de direcciones. Solo hay 1 segmento de stack, SS, y apunta a exactamente lo mismo que DS, ES y CS hacen [2]. Es decir, todo el maldito espacio de usuario . 0-2GB. Por supuesto, eso no significa que los hilos solo tengan 1 stack. Naturalmente, cada uno tiene su propia stack, pero los segmentos x86 no se utilizan para este propósito.

    Tal vez * nix hace algo diferente. Quién sabe. La premisa en la que se basaba la pregunta estaba rota.


    1. Al menos para el espacio de usuario.
    2. Desde el ntsd notepad : cs=001b ss=0023 ds=0023 es=0023

    En general, los hilos se llaman proceso de peso ligero. Si dividimos la memoria en tres secciones, será: código, datos y stack. Cada proceso tiene su propio código, datos y secciones de stack y, debido a este contexto, el tiempo de conmutación es un poco alto. Para reducir el tiempo de cambio de contexto, las personas han creado el concepto de hilo, que comparte Datos y segmento de código con otro hilo / proceso y tiene su propio segmento de APILAMIENTO.

    Un proceso tiene segmentos de código, datos, montón y stack. Ahora, el Puntero de Instrucción (IP) de un subproceso O subprocesos apunta al segmento de código del proceso. Los segmentos de datos y montón son compartidos por todos los hilos. ¿Y ahora qué hay del área de stack? ¿Cuál es en realidad el área de stack? Es un área creada por el proceso solo para usar su hilo … porque las stacks se pueden usar de una manera mucho más rápida que montones, etc. El área de stack del proceso se divide entre hilos, es decir, si hay 3 hilos, entonces el El área de stack del proceso se divide en 3 partes y cada una se asigna a los 3 hilos. En otras palabras, cuando decimos que cada hilo tiene su propia stack, esa stack es en realidad una parte del área de stack de proceso asignada a cada hilo. Cuando un hilo termina su ejecución, el proceso reclama la stack del hilo. De hecho, no solo la stack de un proceso se divide entre hilos, sino que todo el conjunto de registros que utiliza un hilo como SP, PC y registros de estado son los registros del proceso. Por lo tanto, cuando se trata de compartir, el código, las áreas de datos y el montón se comparten, mientras que el área de stack simplemente se divide entre subprocesos.

    Los subprocesos comparten el código y los segmentos de datos y el montón, pero no comparten la stack.

    Los subprocesos comparten datos y códigos mientras que los procesos no. La stack 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 copy-on-write . No estoy seguro de la semántica exacta para el código de subprocesos, pero supongo que el código compartido.

                Proceso de hilo
    
        Astackr privado privado
        Datos privados compartidos
        Código privado 1 compartido 2
    

    1 El código es lógicamente privado, pero se puede compartir por motivos de rendimiento. 2 No estoy 100% seguro.

    Los hilos comparten todo [1]. Hay un espacio de direcciones para todo el proceso.

    Cada hilo tiene su propia stack y registros, pero todas las stacks de hilos están visibles en el espacio de direcciones compartido.

    Si un subproceso asigna algún objeto en su stack 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 archivo ejecutable (por ejemplo, ELF) tiene secciones distintas, que pueden denominarse segmentos, que contienen código comstackdo (texto), datos inicializados, símbolos del vinculador, información de depuración, etc. No hay segmentos de stack o stack aquí, ya que son construcciones solo de tiempo de ejecución.

    Estos segmentos de archivos binarios se pueden mapear en el espacio de direcciones del proceso por separado, con diferentes permisos (por ejemplo, ejecutable de solo lectura para código / texto, y copia-en-escritura no ejecutable para datos inicializados).

    Las áreas de este espacio de direcciones se usan para diferentes propósitos, como asignación de montón y stacks de subprocesos, por convención (impuesta 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 8086 virtual. La stack de cada subproceso es una porción de memoria asignada en el momento de creación del subproceso, con la dirección actual de la stack almacenada en un registro de puntero de stack, y cada subproceso mantiene su propio puntero de stack junto con sus otros registros.


    [1] Está bien, lo sé: máscaras de señal, TSS / TSD, etc. Sin embargo, el espacio de direcciones, incluidos todos sus segmentos de progtwig mapeados, aún se comparten.

    En un marco x86, uno puede dividir tantos segmentos (hasta 2 ^ 16-1). Las directivas ASM SEGMENT / ENDS lo permiten, y los operadores SEG y OFFSET permiten la inicialización de registros de segmento. CS: IP generalmente son inicializados por el cargador, pero para DS, ES, SS, la aplicación es responsable de la inicialización. Muchos entornos permiten las denominadas “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 los registros de segmento en consecuencia. Por lo general, los archivos .data, .bss, .stack y otros segmentos usuales (no lo he hecho desde hace 20 años, así que no lo recuerdo todo) están agrupados en un solo grupo, es por eso que, por lo general, DS, ES y SS apuntan a misma área, pero esto es solo para simplificar las cosas.

    En general, todos los registros de segmentos pueden tener diferentes valores en el tiempo de ejecución. Entonces, la pregunta de la entrevista era correcta: cuál de los CÓDIGOS, DATOS y PILA se comparten entre los hilos. La gestión de heap 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? ¿Todavía puede tener nuevo / eliminar en su código?

    Mi consejo para los jóvenes: leer un buen libro de progtwigción de ensamblaje. Parece que los planes de estudios universitarios son bastante pobres en este sentido.

    Thread comparte el montón (hay una investigación sobre el montón específico de subprocesos) pero la implementación actual comparte el montón. (y por supuesto el código)

    En proceso, todos los hilos comparten el recurso del sistema, como la memoria de montón, etc., mientras que el hilo tiene su propia stack

    Entonces, tu ans debería ser la memoria dinámica que todos los hilos comparten para un proceso.