23 Oct

Principios de Concurrencia y Sincronización de Procesos

Requisitos de Sincronización:

  • Exclusión Mutua

    Poner correctamente bajo exclusión mutua (ExMut) los recursos compartidos. Si no se hace, se producirán interferencias no deseadas entre procesos, provocando corrupción de datos compartidos. Si esto ocurre, hay una condición de carrera.

  • Ausencia de Interbloqueos (Deadlocks y Livelocks)

    Dos procesos se bloquean mutuamente cuando se están esperando el uno al otro y no pueden continuar su ejecución mientras esperan.

    • Interbloqueo Activo (Livelock): Ocurre cuando los procesos ejecutan instrucciones que no producen un avance real del programa, solo sirven para sincronizarse entre sí.
    • Interbloqueo Pasivo (Deadlock): Ocurre cuando todos los procesos están bloqueados esperando indefinidamente. Este interbloqueo solo se produce con herramientas de sincronización.
  • Ausencia de Retrasos Innecesarios

    Los procesos deben progresar en su ejecución si no hay otro proceso compitiendo con él para entrar en las secciones bajo exclusión mutua.

  • Ausencia de Inanición (Starvation)

    Todo proceso que quiera acceder a un recurso compartido deberá poder hacerlo en algún momento.

Modelos de Comunicación por Pasos de Mensajes

Identificación de Procesos

  • Comunicación Directa Simétrica: El emisor indica el ID del receptor y viceversa. (Esta identificación puede hacer el sistema poco flexible a futuras ampliaciones).
  • Comunicación Indirecta Asimétrica: El emisor conoce el ID del receptor, pero no al revés. (Es más flexible que el otro, usado en arquitecturas cliente/servidor en sistemas distribuidos).
  • Comunicación Indirecta (Buzones/Buffers): El emisor envía a un búfer o buzón intermedio. Depende de las restricciones aplicadas a estos:
    • Varios procesos pueden recibir mensajes de una misma cola o la cola puede ser exclusiva para cada proceso.
    • Un mensaje enviado a una cola puede ser recibido por un único proceso o por todos.
    • Un mismo proceso puede enviar un mensaje a varias colas.
    • Las colas pueden ser estáticas o dinámicas.

Sincronización en la Comunicación

  • Comunicación Síncrona: Emisor y receptor coinciden en el mismo instante de la comunicación.
  • Comunicación Asíncrona: Coinciden en el tiempo, pero no en el mismo instante.

Características del Canal de Comunicación

Flujo de datos, capacidad del canal, tipo y tamaño, ordenación y fiabilidad del envío.

Programación Funcional: Expresiones Lambda y Clases Anónimas

Expresiones Lambda

Son una forma compacta de pasar código a un método como parámetro. Se pueden utilizar en todos aquellos lugares en los que se espere un objeto que implementa una interfaz con un único método.

Clases Anónimas

En versiones anteriores, la forma habitual de pasar código como parámetro era usando clases anónimas. Las clases anónimas son una forma compacta de implementar una clase completa dentro de un método. En la misma sentencia se declara la clase y se crea un objeto de dicha clase. Una clase anónima no tiene nombre.

Comparativa: Clases Anónimas vs. Lambda

  • Las expresiones lambda son más eficientes en tiempo de ejecución que las clases anónimas y son más compactas de escribir.
  • Una clase anónima es una clase completa (puede tener clase padre, atributos, etc.). Una lambda solo puede usarse donde se espere una interfaz con un método.
  • Si se usa this en una clase anónima, se referencia al objeto de la clase anónima. Si se hace en lambda, se referencia al objeto donde se está declarando la lambda.

Características de un Lenguaje Funcional

Un lenguaje de programación se puede considerar funcional si permite manejar funciones de las siguientes maneras:

  • Asignar funciones a variables.
  • Pasar funciones como parámetro.
  • Definir funciones anónimas en los mismos lugares que se puede poner un valor o una expresión.

Gestión de Hilos, Thread-Safety y Procesamiento de Datos (Streams)

Objetos Compartidos entre Hilos

Un objeto se puede compartir entre varios hilos sin problemas si se cumplen las siguientes condiciones:

  • Se accede a los métodos bajo exclusión mutua.
  • La clase de ese objeto está preparada para la ejecución concurrente de sus métodos.
  • Los objetos no se modifican durante el tiempo que se comparten entre hilos (la clase es inmutable).

Thread-Safe

Los objetos de la clase Thread-safe se pueden compartir entre hilos sin necesidad de ponerlos bajo exclusión mutua. Todas las clases inmutables son Thread-safe.

Para implementar una clase Thread-safe, hay que asegurarse de que todos sus métodos se pueden ejecutar por varios hilos de forma concurrente sin condiciones de carrera ni intercalaciones no deseadas, lográndolo mediante:

  • Haciendo la clase inmutable.
  • Sincronizando los hilos de alguna manera.
  • Utilizando atributos Thread-safe.

Streams vs. Colecciones

CaracterísticaStreamsColecciones
NaturalezaSecuencia de elementos.Elementos que se pueden procesar en secuencia o con acceso directo.
ProcesamientoInformación volátil que solo se puede procesar una vez. Se calculan según se van procesando.Tienen que estar en memoria antes de procesarse. Estructuras de datos en memoria.
TamañoTamaño infinito.Tamaño finito.
Tipos PrimitivosTiene versiones eficientes para tipos primitivos.No tiene versiones para tipos primitivos.

Operaciones de Streams

  • Intermedias: Se procesan de forma perezosa (ej. map, filter).
  • Terminales: Inician la computación y devuelven un objeto, valor o lista (ej. sum).

Aplicaciones Concurrentes y Bases de Datos

Ejemplos de aplicaciones concurrentes: aplicaciones de interfaz de usuario y aplicaciones web.

Las Bases de Datos están diseñadas para que varios clientes realicen consultas concurrentemente. Se han optimizado según las siguientes estrategias:

Estrategias de Optimización en BBDD

  1. Transacciones: El usuario indica cuándo comienzan y cuándo terminan las operaciones que deben ejecutarse de forma atómica.
  2. Bloqueos: El usuario indica el nivel de exclusión mutua de la BBDD.
    • Bloqueo Pesimista: Los datos se bloquean para que no puedan ser usados por otra transacción mientras la transacción actual los está utilizando. (Puede limitar el rendimiento de la BBDD innecesariamente).
    • Bloqueo Optimista: Los datos no se bloquean. Cuando una transacción está a punto de terminar, se verifica si los datos que se han leído han cambiado durante la transacción. Si han cambiado, se reintenta la transacción. (Ofrece mejor rendimiento si no hay muchas transacciones que usan los mismos datos).

Deja un comentario