Articulo de referencia

Hilo (informática)

Un proceso con dos hilos de ejecución, que se ejecuta en un procesador. Planificación de programas frente a procesos frente a hilos , interrupción , cambio de contexto En inform...

Un proceso con dos hilos de ejecución, que se ejecuta en un procesador.
Planificación de programas frente a procesos frente a hilos , interrupción , cambio de contexto

En informática , un hilo de ejecución es la secuencia más pequeña de instrucciones programadas que puede ser gestionada de forma independiente por un planificador , que normalmente forma parte del sistema operativo . [ 1 ] En muchos casos, un hilo es un componente de un proceso .

Los múltiples hilos de un proceso pueden ejecutarse simultáneamente (mediante capacidades de multihilo), compartiendo recursos como la memoria , mientras que otros procesos no comparten estos recursos. En particular, los hilos de un proceso comparten su código ejecutable y los valores de sus variables asignadas dinámicamente y variables globales no locales a cada hilo en un momento dado.

La implementación de hilos y procesos difiere entre sistemas operativos. [ 2 ]

Historia

Los hilos aparecieron por primera vez con el nombre de "tareas" en el sistema operativo de procesamiento por lotes de IBM, OS/360, en 1967. Ofrecía a los usuarios tres configuraciones disponibles del sistema de control OS/360 , una de las cuales era la multiprogramación con un número variable de tareas (MVT). Saltzer (1966) atribuye a Victor A. Vyssotsky el término "hilo". [ 3 ]

La implementación de hilos en Mach se describió en el verano de 1986. [ 4 ] OS/2 1.0, lanzado en 1987, admitía hilos [ 5 ] . El sistema operativo MP/M de Digital Research proporcionó multiprogramación, multitarea y multitarea preventiva para el procesador Intel 8080 en 1979, y para el procesador 8086 en 1981. La primera versión de Windows que tuvo hilos fue Windows NT , que se lanzó en 1993.

En 1995, el IEEE definió la API pthreads , que estandarizó una interfaz para la programación multihilo portátil en una variedad de sistemas operativos tipo Unix [ 6 ] . Desde entonces, pthreads también se ha implementado en Windows con paquetes de terceros como pthreads-w32 [ 7 ] , que implementa el estándar sobre la API de Windows existente .

El uso de hilos en aplicaciones de software se generalizó a principios de la década de 2000, cuando las CPU comenzaron a utilizar múltiples núcleos. Las aplicaciones que deseaban aprovechar los múltiples núcleos para obtener ventajas de rendimiento debían emplear la concurrencia para utilizarlos. [ 8 ]

La planificación puede realizarse a nivel del núcleo o a nivel de usuario, y la multitarea puede realizarse de forma preventiva o cooperativa . Esto da lugar a una variedad de conceptos relacionados.

Procesos

A nivel del núcleo, un proceso contiene uno o más hilos del núcleo , que comparten los recursos del proceso, como la memoria y los descriptores de archivo; un proceso es una unidad de recursos, mientras que un hilo es una unidad de planificación y ejecución. La planificación del núcleo se realiza normalmente de forma uniforme, de manera preventiva o, con menos frecuencia, de forma cooperativa. A nivel de usuario, un proceso como un sistema de tiempo de ejecución puede planificar por sí mismo múltiples hilos de ejecución. Si estos no comparten datos, como en Erlang , se les suele llamar procesos de forma análoga, [ 9 ] mientras que si comparten datos se les suele llamar hilos (de usuario) , especialmente si se planifican de forma preventiva. Los hilos de usuario planificados de forma cooperativa se conocen como fibras ; diferentes procesos pueden planificar los hilos de usuario de forma diferente. Los hilos de usuario pueden ser ejecutados por hilos del núcleo de diversas maneras (uno a uno, muchos a uno, muchos a muchos). El término proceso ligero se refiere indistintamente a los hilos de usuario o a los mecanismos del núcleo para planificar hilos de usuario en hilos del núcleo.

Un proceso es una unidad pesada de planificación del kernel, ya que crear, destruir y cambiar de proceso es relativamente costoso. Los procesos poseen recursos asignados por el sistema operativo. Los recursos incluyen memoria (tanto para código como para datos), identificadores de archivo , sockets, identificadores de dispositivo, ventanas y un bloque de control de proceso . Los procesos están aislados por el aislamiento de procesos y no comparten espacios de direcciones ni recursos de archivo excepto a través de métodos explícitos como heredar identificadores de archivo o segmentos de memoria compartida, o mapear el mismo archivo de forma compartida (véase Comunicación entre procesos) . Crear o destruir un proceso es relativamente costoso, ya que se deben adquirir o liberar recursos. Los procesos suelen ser multitarea con prioridad, y el cambio de proceso es relativamente costoso, más allá del costo básico del cambio de contexto , debido a problemas como el vaciado de la caché (en particular, el cambio de proceso cambia el direccionamiento de la memoria virtual, lo que provoca la invalidación y, por lo tanto, el vaciado de un búfer de traducción de direcciones (TLB) sin etiquetar, especialmente en x86 ).

Hilos del kernel

Un hilo del kernel es una unidad ligera de planificación del kernel. Existe al menos un hilo del kernel en cada proceso. Si existen varios hilos del kernel en un proceso, comparten la misma memoria y los mismos recursos de archivos. Los hilos del kernel se ejecutan de forma preventiva si el planificador de procesos del sistema operativo es preventivo. Los hilos del kernel no poseen recursos, excepto una pila , una copia de los registros , incluido el contador de programa , y ​​almacenamiento local del hilo (si lo hay), por lo que su creación y destrucción son relativamente económicas. El cambio de hilo también es relativamente económico: requiere un cambio de contexto (guardando y restaurando registros y el puntero de pila), pero no modifica la memoria virtual y, por lo tanto, es compatible con la caché (manteniendo la TLB válida). El kernel puede asignar uno o más hilos de software a cada núcleo de una CPU (pudiendo asignarse a sí mismo varios hilos de software según su compatibilidad con la multihilo) y puede intercambiar los hilos que se bloquean. Sin embargo, el intercambio de hilos del kernel tarda mucho más que el de los hilos de usuario.

Hilos de usuario

En ocasiones, los hilos se implementan en bibliotecas de espacio de usuario , por lo que se denominan hilos de usuario . El núcleo no tiene conocimiento de ellos, por lo que se gestionan y planifican en el espacio de usuario. Algunas implementaciones basan sus hilos de usuario en varios hilos del núcleo para aprovechar las ventajas de las máquinas multiprocesador ( modelo M:N ). Los hilos de usuario implementados mediante máquinas virtuales también se denominan hilos verdes .

Dado que las implementaciones de hilos de usuario suelen estar completamente en el espacio de usuario, el cambio de contexto entre hilos de usuario dentro del mismo proceso es extremadamente eficiente, ya que no requiere ninguna interacción con el núcleo: un cambio de contexto se puede realizar guardando localmente los registros de la CPU utilizados por el hilo de usuario o fibra que se está ejecutando y, a continuación, cargando los registros necesarios para la ejecución del hilo o fibra. Como la planificación se realiza en el espacio de usuario, la política de planificación se puede adaptar más fácilmente a los requisitos de la carga de trabajo del programa.

Sin embargo, el uso de llamadas al sistema bloqueantes en subprocesos de usuario (a diferencia de los subprocesos del kernel) puede ser problemático. Si un subproceso de usuario o una fibra realiza una llamada al sistema que bloquea, los demás subprocesos de usuario y fibras del proceso no pueden ejecutarse hasta que la llamada al sistema finalice. Un ejemplo típico de este problema se da al realizar operaciones de entrada/salida (E/S): la mayoría de los programas están diseñados para realizar E/S de forma síncrona. Cuando se inicia una operación de E/S, se realiza una llamada al sistema que no finaliza hasta que la operación se haya completado. Durante este tiempo, todo el proceso queda bloqueado por el kernel y no puede ejecutarse, lo que impide que otros subprocesos de usuario y fibras del mismo proceso se ejecuten.

Una solución común a este problema (utilizada, en particular, por muchas implementaciones de hilos ligeros) consiste en proporcionar una API de E/S que implemente una interfaz que bloquee el hilo que realiza la llamada, en lugar de todo el proceso, mediante el uso interno de E/S no bloqueante y la programación de otro hilo de usuario o fibra mientras la operación de E/S está en curso. Se pueden proporcionar soluciones similares para otras llamadas al sistema bloqueantes. Alternativamente, el programa puede escribirse para evitar el uso de E/S síncrona u otras llamadas al sistema bloqueantes (en particular, utilizando E/S no bloqueante, incluyendo continuaciones lambda y/o primitivas async/ await [ 10 ] ).

Fibras

Las fibras son una unidad de planificación aún más ligera que se planifica de forma cooperativa : una fibra en ejecución debe ceder explícitamente el paso para permitir que otra fibra se ejecute, lo que hace que su implementación sea mucho más sencilla que la de los hilos del kernel o de usuario . Una fibra puede planificarse para ejecutarse en cualquier hilo del mismo proceso. Esto permite que las aplicaciones obtengan mejoras de rendimiento al gestionar la planificación por sí mismas, en lugar de depender del planificador del kernel (que puede no estar optimizado para la aplicación). Algunas implementaciones de investigación del modelo de programación paralela OpenMP implementan sus tareas a través de fibras. [ 11 ] [ 12 ] Estrechamente relacionadas con las fibras están las corrutinas , con la distinción de que las corrutinas son una construcción a nivel de lenguaje, mientras que las fibras son una construcción a nivel de sistema.

Hilos frente a procesos

Los hilos se diferencian de los procesos multitarea tradicionales del sistema operativo en varios aspectos:

Se dice que sistemas como Windows NT y OS/2 tienen subprocesos baratos y procesos caros ; en otros sistemas operativos no hay tanta diferencia, excepto en el coste de un cambio de espacio de direcciones , que en algunas arquitecturas (en particular x86 ) da como resultado un vaciado del búfer de traducción anticipada (TLB).

Las ventajas y desventajas de los hilos frente a los procesos incluyen:

  • Menor consumo de recursos de los hilos: al usar hilos, una aplicación puede funcionar con menos recursos de los que necesitaría si utilizara múltiples procesos.
  • Simplificación del intercambio y la comunicación entre hilos: a diferencia de los procesos, que requieren un mecanismo de paso de mensajes o de memoria compartida para realizar la comunicación entre procesos (IPC), los hilos pueden comunicarse a través de datos, código y archivos que ya comparten.
  • Un hilo puede provocar el bloqueo de un proceso : debido a que los hilos comparten el mismo espacio de direcciones, una operación ilegal realizada por un hilo puede provocar el bloqueo de todo el proceso; por lo tanto, un hilo que se comporta de forma anómala puede interrumpir el procesamiento de todos los demás hilos de la aplicación.

Programación

Planificación preventiva frente a planificación cooperativa

Los sistemas operativos programan los hilos de forma preventiva o cooperativa . Los sistemas operativos multiusuario generalmente prefieren la programación preventiva para un control más preciso del tiempo de ejecución mediante el cambio de contexto . Sin embargo, la programación preventiva puede provocar cambios de contexto en los hilos en momentos inesperados para los programadores, lo que puede causar bloqueos en cadena , inversión de prioridad u otros efectos secundarios. Por el contrario, la programación cooperativa se basa en que los hilos cedan el control de la ejecución, asegurando así que se completen . Esto puede causar problemas si un hilo con multitarea cooperativa se bloquea esperando un recurso o si impide que otros hilos accedan a él al no ceder el control de la ejecución durante un cálculo intensivo.

Sistemas de un solo procesador frente a sistemas multiprocesador

Hasta principios de la década de 2000, la mayoría de las computadoras de escritorio tenían una sola CPU de un solo núcleo, sin soporte para subprocesos de hardware , aunque estos se seguían utilizando en dichas computadoras porque el cambio entre subprocesos generalmente seguía siendo más rápido que los cambios de contexto de proceso completos . En 2002, Intel agregó soporte para multihilo simultáneo al procesador Pentium 4 , bajo el nombre de hyper-threading ; en 2005, presentaron el procesador de doble núcleo Pentium D y AMD presentó el procesador de doble núcleo Athlon 64 X2 .

Los sistemas con un solo procesador generalmente implementan la multihilo mediante la división del tiempo : la unidad central de procesamiento (CPU) cambia entre diferentes hilos de software . Este cambio de contexto suele ocurrir con la suficiente frecuencia como para que los usuarios perciban que los hilos o tareas se ejecutan en paralelo (en los sistemas operativos populares para servidores y ordenadores de escritorio, el tiempo máximo de ejecución de un hilo, mientras otros hilos esperan, suele estar limitado a 100-200 ms). En un sistema multiprocesador o multinúcleo , varios hilos pueden ejecutarse en paralelo , y cada procesador o núcleo ejecuta un hilo independiente simultáneamente; en un procesador o núcleo con hilos de hardware , los hilos de software independientes también pueden ejecutarse concurrentemente mediante hilos de hardware independientes.

Modelos de enhebrado

1:1 (hilos a nivel de kernel)

Los hilos creados por el usuario en correspondencia uno a uno con entidades programables en el núcleo [ 13 ] son ​​la implementación de hilos más simple posible. OS/2 y Win32 utilizaron este enfoque desde el principio, mientras que en Linux la biblioteca GNU C implementa este enfoque (a través de NPTL o la versión anterior LinuxThreads ). Este enfoque también lo utilizan Solaris , NetBSD , FreeBSD , macOS e iOS .

M : 1 (subprocesos a nivel de usuario)

Un modelo M :1 implica que todos los hilos de nivel de aplicación se asignan a una entidad programada de nivel de kernel; [ 13 ] el kernel no tiene conocimiento de los hilos de la aplicación. Con este enfoque, el cambio de contexto se puede realizar muy rápidamente y, además, se puede implementar incluso en kernels simples que no admiten hilos. Sin embargo, uno de los principales inconvenientes es que no puede beneficiarse de la aceleración de hardware en procesadores multihilo o computadoras multiprocesador : nunca hay más de un hilo programado al mismo tiempo. [ 13 ] Por ejemplo: si uno de los hilos necesita ejecutar una solicitud de E/S, todo el proceso se bloquea y no se puede utilizar la ventaja de los hilos. GNU Portable Threads utiliza hilos de nivel de usuario, al igual que State Threads .

M : N (enhebrado híbrido)

M : N asigna M hilos de aplicación a N entidades del kernel, [ 13 ] o "procesadores virtuales". Esto representa un compromiso entre la programación de hilos a nivel del kernel ("1:1") y a nivel de usuario (" N :1"). En general, los sistemas de programación de hilos " M : N " son más complejos de implementar que los hilos del kernel o de usuario, ya que requieren cambios tanto en el código del kernel como en el del espacio de usuario . En la implementación M:N, la biblioteca de programación de hilos se encarga de planificar los hilos de usuario en las entidades planificables disponibles; esto hace que el cambio de contexto de los hilos sea muy rápido, ya que evita las llamadas al sistema. Sin embargo, esto aumenta la complejidad y la probabilidad de inversión de prioridad , así como la planificación subóptima sin una coordinación extensa (y costosa) entre el planificador del espacio de usuario y el planificador del kernel.

Ejemplos de implementación híbrida

  • Activaciones del planificador utilizadas por versiones anteriores de la implementación de la biblioteca de subprocesos POSIX nativa de NetBSD (un modelo M : N en contraposición a un modelo de implementación de espacio de usuario o kernel 1:1).
  • Procesos ligeros utilizados por versiones anteriores del sistema operativo Solaris.
  • Marcel, del proyecto PM2 .
  • El sistema operativo para el Tera- Cray MTA-2
  • El compilador Glasgow Haskell (GHC) para el lenguaje Haskell utiliza hilos ligeros que se programan en los hilos del sistema operativo.

Historia de los modelos de subprocesos en los sistemas Unix

SunOS 4.x implementó procesos ligeros o LWP. NetBSD 2.x+ y DragonFly BSD implementan LWP como hilos del kernel (modelo 1:1). SunOS 5.2 a SunOS 5.8, así como NetBSD 2 a NetBSD 4, implementaron un modelo de dos niveles, multiplexando uno o más hilos de nivel de usuario en cada hilo del kernel (modelo M:N). SunOS 5.9 y posteriores, así como NetBSD 5, eliminaron el soporte para hilos de usuario, volviendo a un modelo 1:1. [ 14 ] FreeBSD 5 implementó el modelo M:N. FreeBSD 6 admitía tanto 1:1 como M:N; los usuarios podían elegir cuál debía usarse con un programa dado mediante /etc/libmap.conf. A partir de FreeBSD 7, el 1:1 se convirtió en el predeterminado. FreeBSD 8 ya no admite el modelo M:N.

Programas de un solo hilo frente a programas multihilo

En programación informática , el procesamiento de un solo hilo consiste en procesar una instrucción a la vez. [ 15 ] En el análisis formal de la semántica de las variables y el estado del proceso, el término " un solo hilo " puede usarse de manera diferente para referirse a "retroceso dentro de un solo hilo", lo cual es común en la comunidad de programación funcional . [ 16 ]

La programación multihilo se encuentra principalmente en sistemas operativos multitarea. Es un modelo de programación y ejecución muy extendido que permite la existencia de múltiples hilos dentro de un mismo proceso. Estos hilos comparten los recursos del proceso, pero pueden ejecutarse de forma independiente. El modelo de programación multihilo proporciona a los desarrolladores una útil abstracción de la ejecución concurrente. La programación multihilo también puede aplicarse a un proceso para habilitar la ejecución paralela en un sistema multiprocesador .

Las bibliotecas de multihilo suelen proporcionar una llamada a función para crear un nuevo hilo, que recibe una función como parámetro. A continuación, se crea un hilo concurrente que comienza a ejecutar la función pasada y finaliza cuando esta devuelve un valor. Estas bibliotecas también ofrecen funciones de sincronización de datos.

Hilos y sincronización de datos

Los hilos de un mismo proceso comparten el mismo espacio de direcciones. Esto permite que el código que se ejecuta simultáneamente se acople estrechamente e intercambie datos de forma conveniente, sin la sobrecarga ni la complejidad de una comunicación entre procesos (IPC) . Sin embargo, cuando se comparten entre hilos, incluso las estructuras de datos simples se vuelven propensas a condiciones de carrera si requieren más de una instrucción de CPU para actualizarse: dos hilos pueden intentar actualizar la estructura de datos al mismo tiempo y encontrarse con que cambia inesperadamente. Los errores causados ​​por condiciones de carrera pueden ser muy difíciles de reproducir y aislar.

Para evitar esto, las interfaces de programación de aplicaciones (API) para subprocesos ofrecen primitivas de sincronización, como los mutex , para bloquear las estructuras de datos e impedir el acceso concurrente. En sistemas monoprocesador, un subproceso que encuentra un mutex bloqueado debe entrar en estado de espera y, por lo tanto, provocar un cambio de contexto. En sistemas multiprocesador, el subproceso puede, en cambio, consultar el mutex mediante un spinlock . Ambas opciones pueden mermar el rendimiento y obligar a los procesadores en sistemas de multiprocesamiento simétrico (SMP) a competir por el bus de memoria, especialmente si la granularidad del bloqueo es demasiado fina.

Otras API de sincronización incluyen variables de condición , secciones críticas , semáforos y monitores .

grupos de subprocesos

Un patrón de programación popular que utiliza hilos es el de grupos de hilos, donde se crea un número determinado de hilos al inicio que esperan a que se les asigne una tarea. Cuando llega una nueva tarea, el hilo se activa, la completa y vuelve a esperar. Esto evita las funciones de creación y destrucción de hilos, que son relativamente costosas para cada tarea, y libera al desarrollador de la gestión de hilos, dejándola en manos de una biblioteca o del sistema operativo, que está mejor capacitado para optimizarla.

Si todos los subprocesos están ocupados, se colocan elementos de trabajo adicionales en una cola hasta que un subproceso esté disponible para ejecutarlos. [ 17 ]

Programas multihilo frente a programas de un solo hilo: ventajas y desventajas

Las aplicaciones multihilo presentan las siguientes ventajas frente a las de un solo hilo:

  • Capacidad de respuesta : el uso de subprocesos múltiples permite que una aplicación responda a las entradas del usuario. En un programa de un solo subproceso, si el subproceso principal se bloquea en una tarea de larga duración, la aplicación puede parecer congelada. Al trasladar estas tareas de larga duración a un subproceso de trabajo que se ejecuta simultáneamente con el subproceso principal, la aplicación puede seguir respondiendo a las entradas del usuario mientras ejecuta tareas en segundo plano. Por otro lado, en la mayoría de los casos, el uso de subprocesos múltiples no es la única forma de mantener la capacidad de respuesta de un programa, ya que se pueden utilizar señales de E/S no bloqueantes o de Unix para obtener resultados similares. [ 18 ]
  • Paralelización : las aplicaciones que buscan utilizar sistemas multinúcleo o multi-CPU pueden usar multihilo para dividir datos y tareas en subtareas paralelas y dejar que la arquitectura subyacente gestione cómo se ejecutan los hilos, ya sea concurrentemente en un núcleo o en paralelo en varios núcleos. Los entornos de computación GPU como CUDA , OpenCL y DirectX 12 utilizan el modelo de multihilo donde decenas o cientos de hilos se ejecutan en paralelo sobre los datos en un gran número de núcleos . Esto, a su vez, permite una mejor utilización del sistema y (siempre que los costos de sincronización no absorban los beneficios) puede proporcionar una ejecución de programas más rápida.

Las aplicaciones multihilo presentan los siguientes inconvenientes:

  • Complejidad de sincronización y errores relacionados: al usar recursos compartidos típicos de programas multihilo, el programador debe tener cuidado para evitar condiciones de carrera y otros comportamientos poco intuitivos. Para que los datos se manipulen correctamente, los hilos a menudo necesitarán coincidir en el tiempo para procesar los datos en el orden correcto. Los hilos también pueden requeriroperaciones mutuamente excluyentes (a menudo implementadas usando mutexes ) para evitar que los datos comunes se lean o sobrescriban en un hilo mientras otro los modifica. El uso descuidado de tales primitivas puede llevar a interbloqueos , bloqueos permanentes o condiciones de carrera por los recursos. Además, el multihilo puede aumentar el uso de recursos del sistema , incluida la RAM . [ 19 ] Como escribió Edward A. Lee : «Aunque los hilos parecen ser un pequeño paso desde la computación secuencial, de hecho, representan un paso enorme. Descartan las propiedades más esenciales y atractivas de la computación secuencial: comprensibilidad, predictibilidad y determinismo. Los hilos, como modelo de computación, son tremendamente no deterministas, y la tarea del programador se convierte en la de podar ese no determinismo». [ 20 ]
  • La imposibilidad de probarlos . En general, los programas multihilo no son deterministas y, por lo tanto, son imposibles de probar. En otras palabras, un programa multihilo puede tener fácilmente errores que nunca se manifiestan en un sistema de prueba, sino solo en producción. [ 21 ] [ 20 ] Esto se puede mitigar restringiendo las comunicaciones entre hilos a ciertos patrones bien definidos (como el paso de mensajes).
  • Costos de sincronización . Dado que el cambio de contexto de subprocesos en las CPU modernas puede costar hasta 1 millón de ciclos de CPU, [ 22 ] resulta difícil escribir programas multihilo eficientes. En particular, se debe prestar especial atención para evitar que la sincronización entre subprocesos sea demasiado frecuente.

Compatibilidad con lenguajes de programación

Muchos lenguajes de programación admiten el uso de hilos en alguna medida.

  • IBM PL/I (F) incluía soporte para multihilo (denominado multitarea ) ya a finales de la década de 1960, y esta funcionalidad se mantuvo en el Optimizing Compiler y versiones posteriores. El compilador IBM Enterprise PL/I introdujo una nueva API de modelo de "hilo". Ninguna de las dos versiones formaba parte del estándar PL/I.
  • Muchas implementaciones de C y C++ admiten subprocesos y proporcionan acceso a las API nativas de subprocesos del sistema operativo. Una interfaz estandarizada para la implementación de subprocesos es POSIX Threads (Pthreads), que consiste en un conjunto de llamadas a bibliotecas de funciones de C. Los proveedores de sistemas operativos pueden implementar la interfaz según sus necesidades, pero el desarrollador de la aplicación debería poder usar la misma interfaz en múltiples plataformas. La mayoría de las plataformas Unix , incluyendo Linux, admiten Pthreads. Microsoft Windows tiene su propio conjunto de funciones de subprocesos en la interfaz process.h para multiprocesos, como beginthread.
  • Algunos lenguajes de programación de alto nivel (y generalmente multiplataforma ), como Java , Python y los lenguajes de .NET Framework , exponen el uso de subprocesos a los desarrolladores, abstraiendo las diferencias específicas de la plataforma en las implementaciones de subprocesos en tiempo de ejecución. Otros lenguajes de programación y extensiones de lenguaje también intentan abstraer completamente el concepto de concurrencia y subprocesos para el desarrollador ( Cilk , OpenMP , Message Passing Interface (MPI)). Algunos lenguajes están diseñados para el paralelismo secuencial (especialmente usando GPU), sin requerir concurrencia ni subprocesos ( Ateji PX , CUDA ).
  • Algunos lenguajes de programación interpretados tienen implementaciones (por ejemplo, Ruby MRI para Ruby, CPython para Python) que admiten subprocesos y concurrencia, pero no la ejecución paralela de subprocesos, debido a un bloqueo global del intérprete (GIL). El GIL es un bloqueo de exclusión mutua que mantiene el intérprete y que puede impedir que este interprete simultáneamente el código de la aplicación en dos o más subprocesos a la vez. Esto limita efectivamente el paralelismo en sistemas multinúcleo. También limita el rendimiento de los subprocesos que dependen del procesador (que lo requieren), pero no afecta tanto a los que dependen de E/S o de la red. Otras implementaciones de lenguajes de programación interpretados, como Tcl con la extensión Thread, evitan la limitación del GIL mediante un modelo Apartment, donde los datos y el código deben "compartirse" explícitamente entre subprocesos. En Tcl, cada subproceso tiene uno o más intérpretes.
  • En modelos de programación como CUDA , diseñados para la computación paralela de datos , un conjunto de hilos ejecuta el mismo código en paralelo, utilizando únicamente su identificador para acceder a los datos en memoria. En esencia, la aplicación debe diseñarse de manera que cada hilo realice la misma operación en diferentes segmentos de memoria, permitiendo así la ejecución en paralelo y el aprovechamiento de la arquitectura de la GPU.
  • Los lenguajes de descripción de hardware, como Verilog, tienen un modelo de subprocesos diferente que admite un número extremadamente grande de subprocesos (para el modelado de hardware).

Véase también

Referencias

  1. Lamport, Leslie (septiembre de 1979). "Cómo hacer una computadora multiprocesador que ejecute correctamente programas multiproceso" (PDF) . IEEE Transactions on Computers . C-28 (9): 690– 691. Bibcode : 1979ITCmp.100..690L . doi : 10.1109/tc.1979.1675439 . S2CID 5679366 . 
  2. Tanenbaum, Andrew S. (1992). Sistemas operativos modernos . Prentice-Hall International Editions. ISBN 0-13-595752-4.
  3. Saltzer, Jerome Howard (julio de 1966). Control de tráfico en un sistema informático multiplexado (PDF) (tesis doctoral). pág. 20. 
  4. "Mach: Una nueva base de núcleo para el desarrollo de UNIX" (PDF) . Actas de la Conferencia y Exposición Técnica USENIX de Verano de 1986. 1986. pág. 93. 
  5. "Guía del programador del sistema operativo Microsoft/2" (PDF) .
  6. "Estándar para la tecnología de la información: Interfaz de sistema operativo portátil (POSIX™) - Interfaz de programación de aplicaciones (API) del sistema, Enmienda 2: Extensión de subprocesos (lenguaje C)" . Asociación de Estándares IEEE . Consultado el 11 de diciembre de 2025 .
  7. "Pthread Win-32: Nivel de conformidad con los estándares" . 22/12/2006. Archivado del original el 11/06/2010 . Consultado el 29/08/2010 .
  8. Sutter, Herb (marzo de 2005). "Se acabó el almuerzo gratis: un giro fundamental hacia la concurrencia en el software" . Dr. Dobb's Journal . 30 (3).
  9. "Erlang: 3.1 Procesos" .
  10. Ignatchenko, Sergey. Ocho maneras de manejar retornos no bloqueantes en programas de paso de mensajes: de C++98 a través de C++11 a C++20 . CPPCON. Archivado del original el 25/11/2020 . Recuperado el 24/11/2020 .{{cite AV media}}: CS1 maint: bot: estado de la URL original desconocido ( enlace )
  11. Ferat, Manuel; Pereira, Romain; Roussel, Adrien; Carribault, Patrick; Steffenel, Luiz-Angelo; Gautier, Thierry (septiembre de 2022). "Mejora de las aplicaciones basadas en tareas MPI+OpenMP para arquitecturas heterogéneas con soporte para GPU" (PDF) . OpenMP en un mundo moderno: del soporte multidispositivo a la metaprogramación . IWOMP 2022: 18.º Taller Internacional sobre OpenMP. Lecture Notes in Computer Science. Vol. 13527. págs. 3–16 . doi : 10.1007/978-3-031-15922-0_1 . ISBN   978-3-031-15921-3. S2CID 251692327 . 
  12. Iwasaki, Shintaro; Amer, Abdelhalim; Taura, Kenjiro; Seo, Sangmin; Balaji, Pavan. BOLT: Optimización de regiones paralelas OpenMP con subprocesos a nivel de usuario (PDF) . XXVIII Conferencia Internacional sobre Arquitecturas Paralelas y Técnicas de Compilación.
  13. 1 2 3 4 Silberschatz, Abraham ; Galvin, Peter Baer; Gagne, Greg (2013). Conceptos de sistemas operativos (9.ª ed.). Hoboken, NJ: Wiley. págs. 170–171 . ISBN   9781118063330.
  14. "Multiprocesamiento en el entorno operativo Solaris" (PDF) . 2002. Archivado del original (PDF) el 26 de febrero de 2009.
  15. Menéndez, Raúl; Lowe, Doug (2001). Murach's CICS for the COBOL Programmer . Mike Murach & Associates. pág. 512. ISBN  978-1-890774-09-7.
  16. O'Hearn, Peter William; Tennent, RD (1997). Lenguajes tipo ALGOL . Vol. 2. Birkhäuser Verlag . pág. 157. ISBN   978-0-8176-3937-2.
  17. "El grupo de subprocesos administrados - .NET Microsoft Learn" . Microsoft Learn . Consultado el 22 de abril de 2026 .
  18. Ignatchenko, Sergey (agosto de 2010). "Single-Threading: ¿Regreso al futuro?" . Overload (97). ACCU : 16–19 .
  19. Weisner, Rickey C. (marzo de 2012). "Cómo la asignación de memoria afecta el rendimiento en programas multihilo" .
  20. 1 2 Lee, Edward (10 de enero de 2006). "El problema de los hilos" . UC Berkeley.
  21. Ignatchenko, Sergey (agosto de 2015). "Se considera perjudicial el uso de subprocesos múltiples a nivel de lógica de negocio" . Overload (128). ACCU : 4–7 .
  22. 'Sin errores' Hare (12 de septiembre de 2016). "Costos de operación en ciclos de reloj de CPU" .

Lecturas adicionales

  • David R. Butenhof: Programación con hilos POSIX , Addison-Wesley, ISBN 0-201-63392-2
  • Bradford Nichols, Dick Buttlar, Jacqueline Proulx Farell: Programación con Pthreads , O'Reilly & Associates, ISBN 1-56592-115-1
  • Paul Hyde: Programación de hilos en Java , Sams, ISBN 0-672-31585-8
  • Jim Beveridge, Robert Wiener: Aplicaciones multihilo en Win32 , Addison-Wesley, ISBN 0-201-44234-5
  • Uresh Vahalia: Unix Internals: the New Frontiers , Prentice Hall, ISBN 0-13-101908-2