cambios SS 2024-11-25 14:24:09
This commit is contained in:
28
.obsidian/workspace.json
vendored
28
.obsidian/workspace.json
vendored
@@ -4,19 +4,21 @@
|
|||||||
"type": "split",
|
"type": "split",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "56e813a421587f25",
|
"id": "2d0b9251619569b8",
|
||||||
"type": "tabs",
|
"type": "tabs",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "75fd2cd48c9b7660",
|
"id": "f159ed47981f3b40",
|
||||||
"type": "leaf",
|
"type": "leaf",
|
||||||
"state": {
|
"state": {
|
||||||
"type": "image",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "TERCERO/ATR1/images/Captura de pantalla de 2024-11-20 10-54-39.png"
|
"file": "TERCERO/SS/SS 24-25.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-image",
|
"icon": "lucide-file",
|
||||||
"title": "Captura de pantalla de 2024-11-20 10-54-39"
|
"title": "SS 24-25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -75,7 +77,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "horizontal",
|
"direction": "horizontal",
|
||||||
"width": 300
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
},
|
},
|
||||||
"right": {
|
"right": {
|
||||||
"id": "44cf06183e1c1c7d",
|
"id": "44cf06183e1c1c7d",
|
||||||
@@ -172,10 +175,14 @@
|
|||||||
"obsidian-git:Open Git source control": false
|
"obsidian-git:Open Git source control": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "75fd2cd48c9b7660",
|
"active": "f159ed47981f3b40",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"Untitled.md",
|
"Pasted image 20241125141145.png",
|
||||||
|
"Pasted image 20241125141142.png",
|
||||||
|
"TERCERO/SPD/Teoría_2425.md",
|
||||||
|
"TERCERO/SS/SS 24-25.md",
|
||||||
"TERCERO/ATR1/images/Captura de pantalla de 2024-11-20 10-54-39.png",
|
"TERCERO/ATR1/images/Captura de pantalla de 2024-11-20 10-54-39.png",
|
||||||
|
"Untitled.md",
|
||||||
"TERCERO/ATR1/Resolución 1 Parcial ATR1.md",
|
"TERCERO/ATR1/Resolución 1 Parcial ATR1.md",
|
||||||
"TERCERO/IA/images/Pasted image 20241115112854.png",
|
"TERCERO/IA/images/Pasted image 20241115112854.png",
|
||||||
"TERCERO/IA/images/Pasted image 20241115110324.png",
|
"TERCERO/IA/images/Pasted image 20241115110324.png",
|
||||||
@@ -186,14 +193,11 @@
|
|||||||
"conflict-files-obsidian-git.md",
|
"conflict-files-obsidian-git.md",
|
||||||
"TERCERO/IA/Teoría_2425.md",
|
"TERCERO/IA/Teoría_2425.md",
|
||||||
"TERCERO/SPD/P4_SPD.md",
|
"TERCERO/SPD/P4_SPD.md",
|
||||||
"TERCERO/SS/SS 24-25.md",
|
|
||||||
"TERCERO/SS/SS Lab.md",
|
"TERCERO/SS/SS Lab.md",
|
||||||
"TERCERO/SPD/Teoría_2425.md",
|
|
||||||
"TERCERO/SS/images/Pasted image 20241024113018.png",
|
"TERCERO/SS/images/Pasted image 20241024113018.png",
|
||||||
"TERCERO/SS/images/Pasted image 20241024090239.png",
|
"TERCERO/SS/images/Pasted image 20241024090239.png",
|
||||||
"TERCERO/SPD/images/Pasted image 20241022150214.png",
|
"TERCERO/SPD/images/Pasted image 20241022150214.png",
|
||||||
"TERCERO/ATR1/images/Pasted image 20241020204947.png",
|
"TERCERO/ATR1/images/Pasted image 20241020204947.png",
|
||||||
"TERCERO/ATR1/images/Pasted image 20241020204701.png",
|
|
||||||
"SEGUNDO/ADDA/Teoría_2324.md",
|
"SEGUNDO/ADDA/Teoría_2324.md",
|
||||||
"TERCERO/IA/Apuntes Julia.md",
|
"TERCERO/IA/Apuntes Julia.md",
|
||||||
"SEGUNDO/IISSI2/Teoría_2324.md",
|
"SEGUNDO/IISSI2/Teoría_2324.md",
|
||||||
|
|||||||
BIN
Pasted image 20241125141142.png
Normal file
BIN
Pasted image 20241125141142.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
Pasted image 20241125141145.png
Normal file
BIN
Pasted image 20241125141145.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -296,4 +296,77 @@ Cada instancia de un thread tiene sus propios recursos, los cuales hay que prote
|
|||||||
- Aunque el proceso creado se le llama "hijo" **no hay relación lógica** entre ambos, al menos en Windows. En UNIX/Linux/POSIX **sí hay**.
|
- Aunque el proceso creado se le llama "hijo" **no hay relación lógica** entre ambos, al menos en Windows. En UNIX/Linux/POSIX **sí hay**.
|
||||||
- La creación del proceso es asíncrona, **NO** es una "llamada".
|
- La creación del proceso es asíncrona, **NO** es una "llamada".
|
||||||
- En la biblioteca de C: `exec` (UNIX) / `_exec` (Win) funcionan distinto en Windows y UNIX/Linux. En Windows se basa en `CreateProcess` y en UNIX/Linux el proceso actual carga un nuevo programa:
|
- En la biblioteca de C: `exec` (UNIX) / `_exec` (Win) funcionan distinto en Windows y UNIX/Linux. En Windows se basa en `CreateProcess` y en UNIX/Linux el proceso actual carga un nuevo programa:
|
||||||
- `posix spawn` es lo equivalente a `CreateProcess` que básicamente hace: `fork` + `exec`
|
- `posix spawn` es lo equivalente a `CreateProcess` que básicamente hace: `fork` + `exec`
|
||||||
|
# <mark style="background: #FFF3A3A6;">TEMA 6: Control de concurrencia y sincronización</mark>
|
||||||
|
En el tema anterior se trataba como lanzar varios hilos que cooperan para una tarea. También vimos el mecanismo más básico de sincronización: la espera activa. Sin embargo, hay técnicas más complejas.
|
||||||
|
## <mark style="background: #ADCCFFA6;">1. Control de concurrencia y sincronización</mark>
|
||||||
|
Cuando varios hilos cooperan para realizar un trabajo es necesario coordinarlos. Los mecanismos para coordinarlos se pueden dividir en dos grupos:
|
||||||
|
### <mark style="background: #FFB86CA6;">Control de concurrencia</mark>
|
||||||
|
Hay al menos un recurso compartido por varios hilos (variables globales, buffers, la consola, etc.). Esto puede llevar a conflictos, por ejemplo en el uso de la consola:
|
||||||
|
- Un `printf` no habría problema.
|
||||||
|
- Si son varios la secuencia de ejecución no se asegura.
|
||||||
|
- Es complicado usar `getchar`, `scanf` y demás funciones I/O desde varios hilos en ejecución.
|
||||||
|
### <mark style="background: #FFB86CA6;">Sincronización</mark>
|
||||||
|
Uno o varios hilos deben esperar a que otro/s terminen alguna tarea. Ya hemos visto uno de ellos:
|
||||||
|
- `WaitForSingleObject(HandleThread, ...)` espera a que un hilo termine.
|
||||||
|
- `std::thread.join` versión muy simplificada, equivalente a `WaitForSingleObject(pth -> native_handle(), INFINITE);`
|
||||||
|
## <mark style="background: #ADCCFFA6;">2. Sincronización entre hilos</mark>
|
||||||
|
### <mark style="background: #FFB86CA6;">Secciones críticas</mark>
|
||||||
|
Es el mecanismo de control de concurrencia mas fácil. Se trata básicamente de:
|
||||||
|
- Definir una variable tipo `CRITICAL_SECTION` (normalmente global).
|
||||||
|
- Identificar las zonas de código que usan un recurso compartido por distintos hilos.
|
||||||
|
- "Marcarlas" como secciones críticas:
|
||||||
|
- `EnterCriticalSection()` al inicio
|
||||||
|
- `LeaveCriticalSection()` al final
|
||||||
|
- Antes de usar las funciones anteriores debemos asegurarnos de inicializar la sección crítica con `InitializeCriticalSection()` y cuando ya no se vaya a usar más de borrarla con `DeleteCriticalSection()`.
|
||||||
|
<div class="nota"><h4>NOTA</h4><p><code>EnterCriticalSection()</code> bloquea sin timeout. Una vez bloquea, el hilo permanece bloqueado hasta que la sección crítica se libere. Esto hace que los errores sean difíciles de tratar. Se puede subsanar con <code>TryEnterCriticalSection()</code></p></div>
|
||||||
|
### <mark style="background: #FFB86CA6;">Mútex</mark>
|
||||||
|
El funcionamiento es similar a las secciones críticas. Algunas diferencias son:
|
||||||
|
- Tienen nombre y se pueden usar para coordinar hilos en **distintos procesos**.
|
||||||
|
- Permiten timeout.
|
||||||
|
Se usan de la siguiente manera:
|
||||||
|
- El mútex debe estar creado antes de usarlo.
|
||||||
|
- `WaitForSingleObject(HandleMutex, ...)` antes de usar el recurso compartido. La función bloquea el hilo si otro ya "posee" el mútex. Cuando se desbloquea puede devolver `WAIT_OBJECT_0` indicando éxito (y el hilo captura el mútex) o un error.
|
||||||
|
- `ReleaseMutex()` después de usar el recurso compartido.
|
||||||
|
### <mark style="background: #FFB86CA6;">Funciones <code>WaitFor</code></mark>
|
||||||
|
Hemos visto que `WaitForSingleObject()` se bloquea hasta que un hilo termine o el hilo capture el mútex. En general, se llama objetos con bloqueo (waitable objects) a aquellos elementos del SO sobre los que se puede usar una función `WaitFor`.
|
||||||
|
<div class="nota"><h4>NOTA</h4><p>Un waitable object puede estar en el estado <code>signaled</code> (señalado) o <code>nonsignaled</code> (no señalado)</p></div>
|
||||||
|
La función se bloquea si el objeto está `nonsignaled`.
|
||||||
|
### <mark style="background: #FFB86CA6;">Eventos</mark>
|
||||||
|
Los eventos son "notificaciones" de que ha pasado algo en el SO. Se usan de la siguiente manera:
|
||||||
|
- El evento debe estar creado antes de usarlo.
|
||||||
|
- `CreateEvent()`
|
||||||
|
- `WaitForSingleObject(HandleEvento, ...)` se bloquea si el evento está `nonsignaled`. Cuando se desbloquea puede devolver éxito (`WAIT_OBJECT_0`) si está `signaled` o error (`WAIT_TIMEOUT`,`WAIT_ABANDONED`,`WAIT_FAILED`).
|
||||||
|
- Manipular el evento:
|
||||||
|
- `SetEvent()` marca el evento como `signaled`
|
||||||
|
- `ResetEvent()` marca el evento como `nonsignaled`
|
||||||
|
- `PulseEvent()` desbloquea hilo/s esperando en el momento de ejecutarse y el evento pasa a `nonsignaled`.
|
||||||
|
![[Pasted image 20241125141145.png]]
|
||||||
|
### <mark style="background: #FFB86CA6;">Semáforos</mark>
|
||||||
|
Mucho menos usados en Windows que en UNIX/Linux. Un semáforo tiene un contador interno.
|
||||||
|
- El semáforo está abierto (`signaled`) si el contador es mayor que 0.
|
||||||
|
- El semáforo está cerrado (`nonsignaled`) si el contador es 0.
|
||||||
|
Se usan de la siguiente manera:
|
||||||
|
- El semáforo se debe crear antes de usarlo con `CreateSemaphore()`.
|
||||||
|
- `WaitForSingleObject(HandleSemaforo, ...)` se bloquea si el semáforo está cerrado (`nonsignaled`). Cuando se desbloquea puede devolver:
|
||||||
|
- `WAIT_OBJECT_0` el semáforo está abierto. Decrementa el contador en 1 y si llega a 0 el semáforo se cierra.
|
||||||
|
- Otro valor indicando error.
|
||||||
|
- `ReleaseSemaphore()` incrementa el contador en 1
|
||||||
|
### <mark style="background: #FFB86CA6;">Otros mecanismos</mark>
|
||||||
|
- **Interlock:** Se usan en variables compartidas. Permiten incrementar/decrementar una variable sin peligro. Son las más rápidas (frecuentes en drivers).
|
||||||
|
- **Mensajes:** Implementación rara en Windows pero muy comunes en otros SO. Muy útiles para intercambiar y sincronizar datos. En Windows se usan para el sistema de ventanas.
|
||||||
|
## <mark style="background: #ADCCFFA6;">3. Sincronización entre procesos</mark>
|
||||||
|
Es posible usar mútex/eventos/semáforos entre procesos al igual que hacemos con los hilos.
|
||||||
|
### <mark style="background: #FFB86CA6;">Sincronización + datos (named pipes)</mark>
|
||||||
|
Una named pipe permite enviar datos de forma sincronizada entre dos o más procesos. Las principales características son:
|
||||||
|
- Tubería de mensajes: los mensajes enviados por un lado se reciben por el otro en el mismo orden.
|
||||||
|
- Bidireccional: permite a un proceso enviar/recibir con la misma tubería.
|
||||||
|
- Utiliza el paradigma C-S.
|
||||||
|
<div class="nota">
|
||||||
|
<h4>Ejemplo típico: named pipe</h4>
|
||||||
|
<ul>
|
||||||
|
<li>El servidor crea un objeto de sincronización para indicar que se ha creado la named pipe</li>
|
||||||
|
<li>Cada cliente crea su propio objeto de sincronización con el mismo parámetro <code>Name</code> para ver si la named pipe ha sido creada, y luego se bloquea esperando a que la tubería esté creada.</li>
|
||||||
|
<li>Tras crear la tubería, el servidor indica que la tubería existe con el evento de sincronización</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user