我是 Rust 的新手。作为学习练习,我正在尝试编写一个简单的计时器结构,我曾经在C++中编写过。界面和实现如下所示:
pub struct Timer {
handle: Option<std::thread::JoinHandle<()>>,
alive: bool,
}
impl Timer {
pub fn new() {
Timer {
handle: None,
alive: false,
}
}
pub fn start(&'static mut self) {
// Oops! How do I do this?
self.handle = Some(std::thread::spawn(move || {
self.alive = true;
self.loop()
}));
}
pub fn stop(&mut self) {
self.alive = false;
self.handle.unwrap().join()
}
pub fn loop(&self) {
// while alive
}
}
我理解为什么这是一个错误,因为start
函数中的use of moved value: self
,但我想知道我应该如何设计我的结构,以便这样的事情可以工作。在我能想到的每一种情况下,我总是会有双重借款的情况。
我有一种预感,我需要更多地了解内部可变性,但我想在进入更多的兔子洞之前,我会寻求设计指导。
我认为你已经非常接近让它工作了。
只有两个障碍:
-
thread::spawn
不允许共享引用 -
alive
和loop
供您分享此设计
解决方案是双重的:
- 在控制器(
Timer
(和工作线程(闭包(之间拆分事物 - 使用
Arc
在两者之间共享状态,因为禁止引用
这里有一个最小的例子供你玩:
use std::{sync, thread, time};
use std::sync::atomic::{AtomicBool, Ordering};
pub struct Timer {
handle: Option<thread::JoinHandle<()>>,
alive: sync::Arc<AtomicBool>,
}
impl Timer {
pub fn new() -> Timer {
Timer {
handle: None,
alive: sync::Arc::new(AtomicBool::new(false)),
}
}
pub fn start<F>(&mut self, fun: F)
where F: 'static + Send + FnMut() -> ()
{
self.alive.store(true, Ordering::SeqCst);
let alive = self.alive.clone();
self.handle = Some(thread::spawn(move || {
let mut fun = fun;
while alive.load(Ordering::SeqCst) {
fun();
thread::sleep(time::Duration::from_millis(10));
}
}));
}
pub fn stop(&mut self) {
self.alive.store(false, Ordering::SeqCst);
self.handle
.take().expect("Called stop on non-running thread")
.join().expect("Could not join spawned thread");
}
}
fn main() {
let mut timer = Timer::new();
timer.start(|| println!("Hello, World!") );
println!("Feeling sleepy...");
thread::sleep(time::Duration::from_millis(100));
println!("Time for dinner!");
timer.stop();
}
我邀请你一次戳一个洞(即,改变一个与你的示例不同的东西,检查错误消息,并尝试了解差异是如何解决它的(。
在操场上,它为我打印:
Feeling sleepy...
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Time for dinner!
虽然我不会依赖(1("Hello, World!"
出现的次数和(2("Feeling sleepy..."
先出现的次数。
该死的,Atomic
啰嗦...我有点希望有一个get
/set
,SeqCst
(更强的排序(可用。