DEV Community

GoyesDev
GoyesDev

Posted on

[SC] Usando un Mutex como alternativa a los actores

Preguntas

¿Qué es un Mutex y en qué se diferencia de un Lock?

Un Mutex es un tipo de Lock del framework Synchronization usado para sincronizar accesos a una variable a través del método withLock(_:).

El método withLock es equivalente a hacer:

mutex.lock()
defer {
  mutex.unlock()
}
return try body(&value)
Enter fullscreen mode Exit fullscreen mode

Observar que value es un valor inout, que se devuelve el valor generado por try body(&value) y que puede arrojar un error.

La diferencia importante entre Mutex y Lock es que usando Lock, el tipo de dato no es Sendable (tendría que marcarse con @unchecked Sendable). En cambio, Mutex sí es Sendable porque encapsula su valor internamente y controla todo acceso a él.

¿Por qué Apple introdujo un Mutex si ya existen los actores en Swift Concurrency?

Mutex es una aproximación bloqueante síncrona que, en ocasiones, puede servir en lugar de un actor asíncrono. Usar el actor asíncrono implica un "overhead" de "scheduling", además de que el invocador debe estar en un contexto síncrono.

El Mutex es útil cuando el trabajo protegido es breve y el bloqueo es más eficiente que suspender y reanudar una tarea.

¿Desde qué versiones de iOS y macOS está disponible el framework Synchronization?

iOS 18 y macOS 15.

¿Cómo se usa el método withLock y qué tipo de acceso proporciona al valor protegido?

Debido a que el parámetro que recibe withLock es inout, entonces da un acceso por referencia.

withLock se usa pasando un closure que puede modificar el valor protegido y puede retornar algún valor. En el ejemplo del artículo teníamos:

var currentCount: Int {
  count.withLock { currentCount in
    return currentCount
  }
}

func increment() {
  count.withLock { currentCount in
    currentCount += 1
  }
}
Enter fullscreen mode Exit fullscreen mode

¿Cómo permite el Mutex trabajar con tipos no-Sendable como NSBezierPath?

A pesar de que NSBezierPath es no-Sendable, se puede crear un Mutex, constante (let), que envuelva al NSBezierPath y modificar el path protegido.

let path = Mutex<NSBezierPath>(NSBezierPath())

func storeTouch(_ point: NSPoint) {
  path.withLock { path in
    path.move(to: point)
  }
}
Enter fullscreen mode Exit fullscreen mode

¿Qué sucede cuando múltiples hilos intentan adquirir un Mutex al mismo tiempo?

Si un hilo trata de tomar el Mutex y este ya fue tomado, entonces el hilo permanece bloqueado hasta que el Mutex sea liberado.


Recapitulación

¿En qué situaciones concretas es preferible usar un Mutex en lugar de un actor?

¿Cómo se puede lanzar un error desde dentro del closure withLock?


Repaso y reflexión

¿Cuál es la conclusión principal del artículo respecto a la elección entre actores y Mutex?

¿Qué ventajas y desventajas tiene cada herramienta según el contexto del proyecto?


Bibliografía

Top comments (0)