# data[].attributes.body
La concurrencia en general básicamente es la capacidad de ejecutar o de realizar múltiples actividades al mismo tiempo en forma simultánea.

# data[].attributes.body
Una solución de forma concurrente va a ser mucho más sencilla de pensarla o hacerla de forma secuencial, para entenderla y luego poder pensar la concurrencia.

# data[].attributes.headline
2) ¿Pará que la  necesitamos en la programación?

# data[].attributes.subject
2) ¿Pará que la  necesitamos en la programación?

# data[].attributes.body
No usar más ciclos de reloj, dejar de secuencializar. Ilustrar mejor los hechos naturales. No bloquear recursos. Distribuir sistemas.

# data[].attributes.body
Ajustar el modelo de arquitectura de hardware y software.

Incrementar la performance

# data[].attributes.body
PROCESO: programa secuencial (un único flujo de control
que ejecuta una instrucción y cuando esta finaliza ejecuta la
siguiente). Estos procesos van a cooperar y competir por recursos (Monitor, teclado, impresora, etc)

# data[].attributes.body
Cuando dos o más procesos necesitan de un mismo recurso.

# data[].attributes.body
Es una situación en la que dos o más procesos o hilos quedan bloqueados indefinidamente porque cada uno está esperando que el otro libere un recurso que necesita.

# data[].attributes.body
La inanición ocurre cuando un proceso o hilo no puede obtener acceso a los recursos que necesita para ejecutarse, ya sea de manera intermitente o de forma permanente, debido a la prioridad dada a otros procesos.

# data[].attributes.body
Secuencial:

La ejecución sigue una secuencia lineal de instrucciones.

Cada instrucción se ejecuta una después de la otra, en orden.

Un solo flujo de control de ejecución.

Concurrente:

Ejecución de múltiples tareas que avanzan simultáneamente.

Pueden compartir recursos y coexistir en el tiempo.

Cada tarea tiene su propio flujo de control de ejecución.

Paralelo:

Ejecución simultánea de múltiples tareas en diferentes núcleos de CPU o unidades de procesamiento.

Aprovecha la capacidad de sistemas con múltiples núcleos.

Cada tarea tiene su propio hilo de ejecución y se ejecuta de manera independiente.

# data[].attributes.body
Concepto de software no restringido a una arquitectura particular de hardware ni a un número determinado de procesadores.

# data[].attributes.body
Un programa concurrente especifica dos o más programas secuenciales que pueden ejecutarse concurrentemente en el tiempo como tareas o procesos.

# data[].attributes.body
Un proceso o tarea es un elemento concurrente abstracto que puede ejecutarse simultáneamente con otros procesos o tareas, si el hardware lo permite.

# data[].attributes.body
Dificilmente una tarea cooperativa se pueda llevar adelante sin comunicación, en todos los aspectos.

# data[].attributes.body
Los procesos intercambian información sobre la memoria compartida o actúan coordinadamente sobre datos residentes en ella. No pueden operar en simultaneo.

# data[].attributes.body
Es necesario establecer un canal (lógico o físico) para transmitir información entre procesos. También el lenguaje debe proveer un protocolo adecuado. Para que la comunicación sea efectiva los procesos deben “saber”
cuándo tienen mensajes para leer y cuando deben trasmitir
mensajes.

# data[].attributes.body
Son un mecanismo de sincronización y control de acceso que se utiliza en programación concurrente para evitar condiciones de carrera y garantizar la exclusión mutua. Pueden ser binarios o de Contador.

# data[].attributes.body
Los procesos se SINCRONIZAN por exclusión mutua en el acceso a secciones críticas de código para no ejecutar simultáneamente, y por condición.

# data[].attributes.body
Asegurar que sólo un proceso tenga acceso a un recurso compartido en un instante de tiempo. Si el programa tiene secciones críticas que pueden compartir más de un proceso, evita que dos o más procesos puedan encontrarse
en la misma sección crítica al mismo tiempo.

# data[].attributes.body
Permite bloquear la ejecución de un proceso hasta que se cumpla una condición dada. Ejemplo de los dos mecanismos de sincronización en un problema de utilización de un área de memoria compartida (buffer limitado con productores y consumidores)

# data[].attributes.body
Ocurre cuando dos o más hilos acceden y modifican un recurso compartido al mismo tiempo, lo que puede dar lugar a resultados inesperados y comportamientos no deterministas.

# data[].attributes.body
Un proceso que tiene mayor prioridad puede causar la
suspensión (pre-emption) de otro proceso concurrente.

# data[].attributes.body
Se refiere al tamaño o nivel de detalle de las tareas o unidades de trabajo que se ejecutan de manera concurrente en un sistema. En otras palabras, se trata de la medida de la cantidad de trabajo que se realiza como una unidad atómica independiente. La elección de la granularidad puede tener un impacto significativo en el rendimiento y la eficiencia de la ejecución concurrente. Fina vs Gruesa

# data[].attributes.body
Esto incluye la asignación de recursos compartidos, métodos de acceso a los recursos, bloqueo y liberación de recursos, seguridad y consistencia.

# data[].attributes.body
Una propiedad deseable en sistemas concurrentes es el equilibrio en el acceso a recursos compartidos por todos los procesos.

# data[].attributes.body
A un proceso se le asigna recursos que implican más trabajo que el de otro.

# data[].attributes.body
Recursos reusables serialmente: los procesos comparten recursos que pueden usar con exclusión mutua.
Adquisición incremental: los procesos mantienen los recursos que poseen mientras esperar adquirir recursos adicionales.
No-preemption: una vez que son adquiridos por un proceso, los recursos no pueden quitarse de manera forzada sino que sólo son liberados voluntariamente.
Espera cíclica: existe una cadena circular (ciclo) de procesos tal que cada uno tiene un recurso que su sucesor en el ciclo está esperando adquirir.

# data[].attributes.body
Requerimientos de un lenguaje de programación concurrente:
Indicar las tareas o procesos que pueden ejecutarse concurrentemente.
Mecanismos de sincronización.
Mecanismos de comunicación entre los procesos.

# data[].attributes.body
Los procesos no son independientes y comparten recursos.

Los procesos iniciados en un programa concurrente pueden no estar vivos LIVENESS.

No es deterministico. Dificil el debug.

Más tiempo de desarrollo.

Posible reducción de performance por el OVERHEAD

# data[].attributes.body
La Concurrencia es un concepto de software (propiedad del
programa)La Programación Paralela se asocia con la ejecución concurrente en múltiples procesadores que pueden tener memoria compartida, y con un objetivo de incrementar performance (propiedad de la máquina). La Programación Distribuida es un “caso” de concurrencia con
múltiples procesadores y sin memoria compartida.

# data[].attributes.body
Esto implica el uso de técnicas y características de hardware diseñadas para permitir la ejecución concurrente de instrucciones y procesos.

# data[].attributes.body
Máquinas monoprocesador ya no pueden mejorar.

Más procesadores por chip para mayor potencia de cómputo.

Multicores → Cluster de multicores → Consumo.

# data[].attributes.body
Programación concurrente y paralela.

# data[].attributes.body
Jerarquía de memoria. ¿Consistencia?

Diferencias de tamaño y tiempo de acceso.

Localidad temporal y espacial de los datos.

# data[].attributes.attachment_link.readable_text
Diagrama piramidal de la jerarquía de memoria.

La jerarquía de memoria es la organización piramidal de la memoria en niveles que tienen las computadoras.

El objetivo es acercarse el rendimiento de una memoria de gran velocidad al coste de una memoria de baja velocidad, basándose en el principio de cercanía de referencias.​

Los puntos básicos relacionados con la memoria pueden resumirse en:

La cuestión de la capacidad es simple, cuanto más memoria haya disponible, más podrá utilizarse.

La velocidad óptima para la memoria es la velocidad a la que el microprocesador puede trabajar, de modo que no haya tiempos de espera entre cálculo y cálculo, utilizados para traer operandos o guardar resultados.

En suma, el coste de la memoria no debe ser excesivo, para que sea factible construir un equipo accesible.

Los tres factores compiten entre sí, por lo que hay que encontrar un equilibrio.

Las siguientes afirmaciones son válidas:

A menor tiempo de acceso mayor coste.

A mayor capacidad menor coste por bit.

A mayor capacidad menor velocidad.

Se busca entonces contar con capacidad suficiente de memoria, con una velocidad que sirva para satisfacer la demanda de rendimiento y con un coste que no sea excesivo.

Gracias a un principio llamado cercanía de referencias, es factible utilizar una mezcla de los distintos tipos y lograr un rendimiento cercano al de la memoria más rápida.

Los niveles

Los lenguajes de programación actuales generalmente asumen la existencia de únicamente dos niveles de memoria: memoria primaria y memoria secundaria (normalmente en disco). En lenguaje ensamblador, ensamblador en línea, y lenguajes como C y C++, se pueden direccionar datos directamente a los registros de la CPU.

Para poder entender mejor le funcionamiento del PC, vaya a su mediamark mas cercano y pregúntele al pancho de la caja registradora, seguro que le ayuda:

Programadores: deben ser responsables del movimiento entre memoria principal y disco mediante el uso de ficheros.

: el movimiento de datos entre la memoria principal y los niveles de caché es realizado por algoritmos de hardware.

Compiladores: son responsables de optimizar el código de modo que el uso de los registros y la caché sea eficiente.

pc

Database System Concepts (capítulo 10). Abraham Silberschatz, Hank Korth y S. Sudarshan. 7ª edición (2019). McGraw-Hill

# data[].attributes.attachment_link.title
Jerarquía de memoria - Wikipedia, la enciclopedia libre

# data[].attributes.attachment_link.description
La jerarquía de memoria es la organización piramidal de la memoria en niveles que tienen las computadoras. El objetivo es acercarse el rendimiento de una memoria de gran velocidad al coste de una memoria de baja velocidad, basándose en el principio de cercanía de referencias.​ Los puntos básicos relacionados con la memoria pueden resumirse en: La cuestión de la capacidad es simple, cuanto más memoria haya disponible, más podrá utilizarse.

# data[].attributes.body
Interacción modificando datos en la memoria compartida.

# data[].attributes.body
Procesadores conectados por una red.

Memoria local (no hay problemas de consistencia).

Interacción es sólo por pasaje de mensajes.

# data[].attributes.body
Esquemas UMA con bus o crossbar switch (SMP, multiprocesadores simétricos).

Problemas de sincronización y consistencia.

Esquemas NUMA para mayor número de procesadores distribuidos

# data[].attributes.body
1. Inicio de la Computación:

En los primeros días de la informática, las computadoras eran sistemas uniprocesador que ejecutaban una única tarea a la vez. La concurrencia no era un concepto relevante en este contexto.

2. Multiprogramación:

Con la introducción de la multiprogramación en la década de 1960, las computadoras comenzaron a ejecutar múltiples programas en paralelo. Sin embargo, estos programas no se ejecutaban simultáneamente en el nivel de instrucciones individuales, sino que se alternaban rápidamente.

3. Multiprocesadores:

A medida que la tecnología avanzaba, surgieron los sistemas multiprocesadores a finales de la década de 1960 y principios de la década de 1970. Estos sistemas tenían la capacidad de ejecutar múltiples tareas simultáneamente, distribuyendo la carga de trabajo entre varios procesadores.

4. Desarrollo de Técnicas de Sincronización:

En la década de 1970, se comenzaron a desarrollar técnicas de sincronización más avanzadas para gestionar la concurrencia, incluyendo la introducción de semáforos y mutex.

5. Desarrollo de Modelos de Concurrencia:

A medida que los sistemas se volvían más complejos, se desarrollaron modelos de concurrencia para ayudar a entender y gestionar la ejecución concurrente. Modelos como el modelo de actores y el modelo de memoria transaccional surgieron para abordar aspectos específicos de la concurrencia.

6. Avances en Hardware:

A lo largo de las décadas de 1980, 1990 y 2000, los avances en la tecnología de hardware llevaron al desarrollo de sistemas con múltiples núcleos de procesador. Esto permitió una mayor concurrencia a nivel de hardware con la ejecución simultánea de múltiples hilos.

7. Programación Concurrente y Paralela:

La programación concurrente y paralela se volvió más común con el auge de sistemas con múltiples núcleos y la necesidad de aprovechar al máximo los recursos disponibles. Lenguajes de programación modernos, como Java y Python, incluyen bibliotecas y constructores para facilitar la programación concurrente.

8. Desarrollo de Tecnologías como Hyper-Threading:

Tecnologías como Hyper-Threading, introducidas por Intel, permiten que un solo núcleo de procesador ejecute múltiples hilos de manera simultánea, mejorando la eficiencia de la ejecución.

# data[].attributes.body
Los procesos se combinan para la tarea. Sincronización fundamental.

# data[].attributes.body
No logra acceder a los recursos compartidos