【问题标题】:RwLock in a thread::spawn doesn't release the lock线程中的 RwLock::spawn 不会释放锁
【发布时间】:2019-12-18 01:53:06
【问题描述】:

我不确定它为什么挂在my.rw.write();

如果您取消注释 sleep 调用,它可以正常工作。这意味着在执行了 spawn 线程并释放了RwLock 之后,写访问尝试仍然阻塞了主线程。我觉得理论上应该没问题。我哪里错了?

use std::sync::Arc;
use std::sync::RwLock;
use std::{thread, time};

struct MySt {
    num1: i64,
    num2: i64,
    rw: RwLock<Vec<i64>>,
}

fn main() {
    let my = Arc::new(MySt {
        num1: 32,
        num2: 64,
        rw: RwLock::new(vec![1, 2, 3]),
    });
    let my2 = my.clone();
    let t = thread::spawn(move || {
        let mut rw = my2.rw.write().unwrap();
        rw[0] = 5;
        println!("child thread {}, {}, {}, {}", my2.num1, my2.num2, rw[0], rw[1]);
    });
    //thread::sleep(time::Duration::from_millis(1000));
    let mut rw = my.rw.write().unwrap();
    rw[1] = 6;
    println!("main thread {}, {}, {}, {}", my.num1, my.num2, rw[0], rw[1]);
    t.join().unwrap();
}

【问题讨论】:

    标签: multithreading rust spawn rwlock


    【解决方案1】:

    在 spawn 线程执行并释放 RwLock 之后,写访问尝试仍然阻塞主线程

    这是不正确的。添加基本​​调试输出以区分它们表明唯一运行的printlnmain 中的那个。

    无法保证在子线程生成后哪个线程将首先执行。但是,主线程可能会继续运行,因为它已经在运行。如果是这样,它将通过rw 锁定RwLock 并保持锁定直到函数结束。但是,在函数结束之前,主线程会阻塞等待子线程加入。子线程无法完成,因为它必须先获取写锁。您已经创建了一个经典的死锁。

    要解决这个问题,请使用drop 显式解锁锁或添加范围以限制锁的生命周期:

    fn main() {
        let my = Arc::new(MySt {
            num1: 32,
            num2: 64,
            rw: RwLock::new(vec![1, 2, 3]),
        });
        let my2 = my.clone();
        let t = thread::spawn(move || {
            let mut rw = my2.rw.write().unwrap();
            rw[0] = 5;
            println!("thread a {}, {}, {}, {}", my2.num1, my2.num2, rw[0], rw[1]);
        });
        //thread::sleep(time::Duration::from_millis(1000));
        let mut rw = my.rw.write().unwrap();
        rw[1] = 6;
        println!("thread b {}, {}, {}, {}", my.num1, my.num2, rw[0], rw[1]);
        drop(rw);
        t.join().unwrap();
    }
    

    添加sleep 可能会导致子线程先执行。然后它将获取锁并退出,允许主线程继续。

    另见:

    【讨论】:

      【解决方案2】:

      它无法正常工作的原因是当主线程中的锁在子线程中的锁之前执行时我没有释放锁。我修复了它,如下所示。

      use std::sync::Arc;
      use std::sync::RwLock;
      use std::{thread, time};
      
      struct MySt {
          num1: i64,
          num2: i64,
          rw: RwLock<Vec<i64>>,
      }
      
      fn main() {
          let my = Arc::new(MySt {
              num1: 32,
              num2: 64,
              rw: RwLock::new(vec![1, 2, 3]),
          });
          let my2 = my.clone();
          let t = thread::spawn(move || {
              let mut rw = my2.rw.write().unwrap();
              rw[0] = 5;
              println!("child thread {}, {}, {}, {}", my2.num1, my2.num2, rw[0], rw[1]);
          });
          {
              let mut rw = my.rw.write().unwrap();
              rw[1] = 6;
              println!("main thread {}, {}, {}, {}", my.num1, my.num2, rw[0], rw[1]);
          }
          t.join().unwrap();
      }
      

      【讨论】:

        猜你喜欢
        • 2018-11-13
        • 2015-02-16
        • 2016-09-19
        • 1970-01-01
        • 1970-01-01
        • 2014-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多