37 - Concurrencia en Rust - threads y mensajería

37 - Concurrencia en Rust - threads y mensajería

¡Bienvenidos de nuevo a Rustaceo.es! En este artículo exploraremos cómo manejar la concurrencia en Rust utilizando threads y mensajería. Rust nos proporciona herramientas seguras y eficientes para ejecutar múltiples tareas en paralelo sin los errores comunes de la programación concurrente.


🚀 Introducción a la concurrencia en Rust #

La concurrencia nos permite ejecutar múltiples tareas simultáneamente, mejorando el rendimiento de nuestras aplicaciones. Sin embargo, en muchos lenguajes esto puede ser peligroso debido a:

  • Condiciones de carrera: Acceso simultáneo a datos sin sincronización.
  • Interbloqueos (deadlocks): Hilos esperando indefinidamente por recursos bloqueados.
  • Accesos no controlados a memoria: Datos corruptos por acceso no seguro.

Rust soluciona estos problemas con su modelo de propiedad y sistema de tipos, asegurando la seguridad en tiempo de compilación.


🧵 Creación de threads en Rust #

Podemos crear nuevos hilos fácilmente usando std::thread::spawn.

📌 Ejemplo: creación de un hilo secundario #

use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..5 {
            println!("Hilo secundario: {}", i);
            thread::sleep(Duration::from_millis(500));
        }
    });

    for i in 1..3 {
        println!("Hilo principal: {}", i);
        thread::sleep(Duration::from_millis(500));
    }

    handle.join().unwrap();
}

🔹 thread::spawn crea un nuevo hilo. 🔹 join() asegura que el hilo secundario termine antes de continuar.


📬 Comunicación segura entre hilos con mpsc #

El modelo “pasar mensajes” usa mpsc::channel para la comunicación entre hilos de manera segura.

📌 Ejemplo: envío de mensajes entre hilos #

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let mensaje = String::from("¡Hola desde otro hilo!");
        tx.send(mensaje).unwrap();
    });
    
    let recibido = rx.recv().unwrap();
    println!("Mensaje recibido: {}", recibido);
}

🔹 mpsc::channel crea un canal de comunicación. 🔹 tx.send() envía un mensaje desde el hilo secundario. 🔹 rx.recv() recibe el mensaje en el hilo principal.


🔒 Compartición segura de datos con arc y mutex #

Cuando múltiples hilos necesitan modificar datos compartidos, usamos Arc<Mutex<T>> para mantener la seguridad.

📌 Ejemplo: contador compartido entre hilos #

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let contador = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..5 {
        let contador = Arc::clone(&contador);
        let handle = thread::spawn(move || {
            let mut num = contador.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Valor final del contador: {}", *contador.lock().unwrap());
}

🔹 Arc (Atomic Reference Counter): Permite múltiples propietarios del Mutex sin violar reglas de propiedad. 🔹 Mutex (Mutual Exclusion): Evita condiciones de carrera en datos compartidos.


🏆 Conclusión #

Rust ofrece herramientas seguras y eficientes para manejar threads y comunicación entre hilos, evitando errores comunes de la programación concurrente.

Threads (std::thread): Fácil manejo de múltiples hilos. ✔ Mensajería con mpsc: Comunicación sin necesidad de memoria compartida. ✔ Arc<Mutex<T>>: Sincronización segura de datos.

🔮 Próximo paso: Explora cómo combinar estos conceptos en aplicaciones reales como servidores web concurrentes o procesamiento paralelo.

¡Hasta la próxima, Rustaceos!