Rust thread runs more than another

Good afternoon everyone, I’m learning rust and I would like to ask a question, in the code below one thread always works more than the other, there doesn’t seem to be a normal distribution of work between the threads.

I wrote the same code in c++ and it works just as well, can someone help me and tell me where I went wrong in rust?

code:

use std::fmt;
use std::sync::{Arc, Mutex};
use std::thread;
use tokio::time::Duration;
struct Client {
    id: i32,
}
impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Client id: {:?}", self.id)
    }
}
fn main() {
    // ======================
    let client: Client = Client { id: 0 };
    let counter = Arc::new(Mutex::new(client));
    let mut handles = vec![];

    // ======================
    // THREAD 1
    // ======================
    let safe_client_1 = Arc::clone(&counter);
    let thread_1 = thread::spawn(move || loop {
        let mut num = safe_client_1.lock().unwrap();
        num.id += 1;
        print!("thread 1: {}", num);
        thread::sleep(Duration::from_secs(1));
    });
    handles.push(thread_1);

    // ======================
    // THREAD 2
    // ======================
    let safe_client_2 = Arc::clone(&counter);
    let thread_2 = thread::spawn(move || loop {
        let mut num = safe_client_2.lock().unwrap();
        num.id -= 1;
        print!("thread 2: {}", num);
        thread::sleep(Duration::from_secs(1));
    });

    loop {}
}

output:

thread 1: Client id: 1
thread 1: Client id: 2
thread 2: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 2: Client id: -2
thread 2: Client id: -3
thread 2: Client id: -4
thread 2: Client id: -5
thread 2: Client id: -6
thread 2: Client id: -7
thread 1: Client id: -6
thread 2: Client id: -7
thread 2: Client id: -8
thread 2: Client id: -9
thread 2: Client id: -10
thread 2: Client id: -11
thread 2: Client id: -12
thread 2: Client id: -13
thread 2: Client id: -14
thread 2: Client id: -15
thread 2: Client id: -16
thread 2: Client id: -17
thread 2: Client id: -18
thread 2: Client id: -19
thread 2: Client id: -20
thread 2: Client id: -21
thread 2: Client id: -22
thread 2: Client id: -23
thread 2: Client id: -24
thread 2: Client id: -25
thread 2: Client id: -26
thread 2: Client id: -27

Solution code:

use std::fmt;
use std::sync::{Arc, Mutex};
use std::thread;
use tokio::time::Duration;
struct Client {
    id: i32,
}
impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Client id: {:?}", self.id)
    }
}
fn main() {
    // ======================
    let client: Client = Client { id: 0 };
    let counter = Arc::new(Mutex::new(client));

    // ======================
    // THREAD 1
    // ======================
    let safe_client_1 = Arc::clone(&counter);
    let thread_1 = thread::spawn(move || loop {
        let mut num = safe_client_1.lock().unwrap();
        num.id += 1;
        print!("thread 1: {}", num);
        drop(num);
        thread::sleep(Duration::from_secs(1));
    });

    // ======================
    // THREAD 2
    // ======================
    let safe_client_2 = Arc::clone(&counter);
    let thread_2 = thread::spawn(move || loop {
        let mut num = safe_client_2.lock().unwrap();
        num.id -= 1;
        print!("thread 2: {}", num);
        drop(num);

        thread::sleep(Duration::from_secs(1));
    });

    loop {}
}

output:

thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0
thread 1: Client id: 1
thread 2: Client id: 0
thread 2: Client id: -1
thread 1: Client id: 0

>Solution :

You sleep while holding the lock. Do this instead:

let thread_1 = thread::spawn(move || loop {
    let mut num = safe_client_1.lock().unwrap();
    num.id += 1;
    print!("thread 1: {}", num);
    drop(num);
    thread::sleep(Duration::from_secs(1));
});

Leave a Reply