Seguridad en Hilos en .NET: Conceptos y Prácticas Recomendadas

¿Qué es la seguridad en hilos?

La seguridad en hilos (thread safety) se refiere a la capacidad de una clase, método u operación para comportarse correctamente cuando varios hilos acceden simultáneamente al mismo recurso compartido, sin necesidad de mecanismos de sincronización externos.

Por ejemplo, considera este código en C#:

int contador = 0;

void Incrementar()
{
    contador++;
}

La operación contador++ no es atómica; consta de tres pasos: leer, incrementar, escribir. Si varios hilos ejecutan Incrementar al mismo tiempo, pueden perderse algunas sumas, dando un resultado menor al esperado.

Estrategias para lograr seguridad en hilos

1. Uso de lock (mutex)

private readonly object _candado = new object();
private int contador = 0;

public void Incrementar()
{
    lock (_candado)
    {
        contador++;
    }
}

El lock garantiza que solo un hilo ejecute ese bloque a la vez. Fácil de usar, pero tiene costo de rendimiento en alta concurrencia.

2. Operaciones atómicas con Interlocked

private int contador = 0;

public void Incrementar()
{
    Interlocked.Increment(ref contador);
}

Ideal para operaciones simples sobre enteros, sin bloqueos.

3. Colecciones seguras para hilos

  • ConcurrentDictionary<TKey, TValue>
  • ConcurrentQueue<T>
  • ConcurrentBag<T>
  • BlockingCollection<T>

Ejemplo:

var diccionario = new ConcurrentDictionary<string, int>();
diccionario.TryAdd("clave", 42);

4. Modificador volatile

private volatile bool _activo;

No resuelve atomicidad, pero garantiza que el valor sea leído desde la memoria principal (no desde caché del CPU), evitando problemas de visibilidad entre hilos.

5. ThreadLocal<T> para datos por hilo

ThreadLocal<int> contadorLocal = new ThreadLocal<int>(() => 0);

void Incrementar()
{
    contadorLocal.Value++;
}

Cada hilo tiene su propia copia, eliminando la contención.

6. Evitar compartir recursos

Diseñar sistemas basados en paso de mensajes (ej. actores con Akka.NET) o colas de mensajes evita la necesidad de sincronización.

Restricción de acceso a la UI desde hilos secundarios

En frameworks .NET como WinForms, WPF, MAUI y Xamarin.Forms, los controles de UI solo pueden ser modificados desde el hilo que los creó (normalmente el hilo principal). Esto no es exactamente un problema de seguridad en hilos tradicional, sino una resrticción del modelo de un solo hilo de UI.

Ejemplo incorrecto (WinForms):

new Thread(() =>
{
    etiqueta.Text = "Actualizando..."; // Lanza InvalidOperationException
}).Start();

Ejemplo correcto (WinForms):

new Thread(() =>
{
    etiqueta.Invoke(() => { etiqueta.Text = "Actualizando..."; });
}).Start();

Ejemplo correcto (WPF):

Application.Current.Dispatcher.Invoke(() =>
{
    textoBloque.Text = "Actualizado desde otro hilo";
});

Comparativa de modelos de hilo en .NET UI

Framework Modelo Método para volver al hilo de UI
Windows Forms Un solo hilo Control.Invoke()/BeginInvoke()
WPF Un solo hilo Dispatcher.Invoke()/BeginInvoke()
.NET MAUI Un solo hilo MainThread.BeginInvokeOnMainThreadAsync()
Xamarin.Forms Un solo hilo Device.BeginInvokeOnMainThread()
Avalonia UI Mayor flexibilidad Dispatcher.UIThread.Post()

Resumen de técnicas

Técnica Cuándo usarla
lock Secciones críticas pequeñas
Interlocked Operaciones atómicas sobre enteros
Colecciones concurrentes Acceso concurrente a colecciones
ThreadLocal<T> Datos independientes por hilo
Diseño sin estado compartido Sistemas de alta concurrencia (actores/mensajes)

Etiquetas: C# seguridad-en-hilos lock Interlocked ConcurrentDictionary

Publicado el 7-18 10:42