我试图解决thread-ring问题。在每个线程中,我读取了令牌值
如果不是我的,请检查它是否是程序结束
如果是我的(即有我的id)然后获取写锁定,增加令牌的值,检查它是否结束然后告诉主线程我完成它并完成当前线程循环
如果没有结束,则释放写锁定,然后再次开始阅读
没有解锁。有没有像我在这里需要的那样解锁?
似乎我也应该释放读锁定,因为如果有人读取数据,写锁定就不会发生。有必要吗?
fn main() {
use std::sync::{Arc, RwLock};
use std::thread;
use std::sync::mpsc::channel;
const N: usize = 5; //503;
const STOP_POINT: usize = 100;
let n = Arc::new(RwLock::new(1));
let (sender, reciever) = channel();
for i in 1..N {
let (n_c, channel) = (n.clone(), sender.clone());
// println!("Thread n.{} beeing created!", i);
let a = thread::Builder::new()
.name(i.to_string())
.spawn(move || -> () {
loop {
let mut read_only = n_c.read().unwrap();
let say_my_name = (*thread::current().name().unwrap()).to_string();
// println!("Thread {} says: gonna try!", say_my_name);
while (*read_only % N) != i {
if *read_only == 0 {
break;
}
// println!("Thread {} says: aint mine!", say_my_name);
read_only = n_c.read().unwrap();
} // WAIT
println!("Thread {} says: my turn!", say_my_name);
let mut ref_to_num = n_c.write().unwrap();
*ref_to_num += 1;
if *ref_to_num == STOP_POINT {
channel.send(say_my_name).unwrap();
break;
}
}
()
});
assert_eq!(a.is_ok(), true);
// thread::spawn();
// println!("Thread n.{} created!", i);
}
println!("{}", reciever.recv().unwrap());
}
答案 0 :(得分:3)
要释放锁定,您可以通过调用drop
让它超出范围或显式调用其析构函数。
以下是在两个地方使用drop
编写程序的方法:
fn main() {
use std::sync::{Arc, RwLock};
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;
const N: usize = 503;
const STOP_POINT: usize = 100;
let n = Arc::new(RwLock::new(1));
let (sender, receiver) = channel();
for i in 1..N {
let (n_c, channel) = (n.clone(), sender.clone());
// println!("Thread n.{} beeing created!", i);
thread::Builder::new()
.name(i.to_string())
.spawn(move || {
loop {
let mut read_only = n_c.read().unwrap();
let say_my_name = (*thread::current().name().unwrap()).to_string();
// println!("Thread {} says: gonna try!", say_my_name);
while (*read_only % N) != i {
if *read_only == 0 {
break;
}
drop(read_only); // release the lock before sleeping
// println!("Thread {} says: aint mine!", say_my_name);
thread::sleep(Duration::from_millis(1));
read_only = n_c.read().unwrap();
}
println!("Thread {} says: my turn!", say_my_name);
drop(read_only); // release the read lock before taking a write lock
let mut ref_to_num = n_c.write().unwrap();
*ref_to_num += 1;
if *ref_to_num == STOP_POINT {
channel.send(say_my_name).unwrap();
break;
}
}
})
.expect("failed to spawn a thread");
// println!("Thread n.{} created!", i);
}
println!("{}", receiver.recv().unwrap());
}
请注意,如果我们不在read_lock
循环中重新分配while
,编译器会发出错误,因为read_lock
在我们之后没有保留有效值致电drop(read_lock)
。对于暂时未初始化的局部变量,Rust很好,但当然我们需要重新初始化它们才能再次使用它们。
这里是如何编写线程的主循环以使用范围来替换drop
之一:
loop {
let say_my_name = (*thread::current().name().unwrap()).to_string();
{
let mut read_only = n_c.read().unwrap();
// println!("Thread {} says: gonna try!", say_my_name);
while (*read_only % N) != i {
if *read_only == 0 {
break;
}
drop(read_only);
thread::sleep(Duration::from_millis(1));
// println!("Thread {} says: aint mine!", say_my_name);
read_only = n_c.read().unwrap();
}
println!("Thread {} says: my turn!", say_my_name);
} // read_only is dropped here
let mut ref_to_num = n_c.write().unwrap();
*ref_to_num += 1;
if *ref_to_num == STOP_POINT {
channel.send(say_my_name).unwrap();
break;
}
}