rust - 更改其他线程中的值并断言后者(在“主”线程中)
问题描述
链接到游乐场(或以下代码):https ://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d6a8e4e6b9fa6aa647b2651e58402aa0
我想为库中的代码编写一个测试。方法外的代码main
与库具有相同的结构(https://github.com/housleyjk/ws-rs/blob/master/src/lib.rs#L110)。
在某些时候,我想提供一个可以在线程中随时间更改的值。我必须稍后在另一个线程中断言该值。困难的部分是,保存变化值的类型的实例化是在FnMut
闭包中构造的。
我试着移动它,我试过RefCell
,我试过,Arc
但我失败了。有什么建议么?
use std::thread::sleep;
use std::time::Duration;
trait Fly {}
trait Surf {
fn will_be_called_after_two_seconds(&mut self);
}
struct Roll;
struct FlyingBird;
impl Fly for FlyingBird {}
struct SurfingDog(bool);
impl Surf for SurfingDog {
fn will_be_called_after_two_seconds(&mut self) {
self.0 = true;
}
}
fn closure_boi<F, S>(x: F) where F: FnMut(Roll) -> S, S: Surf {}
fn main() {
let val = false;
std::thread::spawn(|| {
closure_boi(|_| {
SurfingDog(val)
});
});
sleep(Duration::from_secs(5));
assert_eq!(true, val);
}
解决方案
有几个问题可以阻止上述代码工作:
- 如果 Rust 不能证明使用它的线程不会超过值本身(在这种情况下是一个范围 in
main
),那么 Rust 将不允许您在两个线程之间共享一个值。解决方法是堆分配值并使用Arc
来跟踪它或使用创建线程crossbeam_utils::thread::scope
,这确实提供了这样的保证。由于您可能需要生成的线程来保持并行运行,所以让我们使用Arc
. SurfingDog
不能只包含布尔值,它必须包含对布尔值的引用,或者整个SurfingDog
实例必须在main
. 在当前代码中,其他线程修改的布尔值位于从它接收的闭包中获得的SurfingDog
值中,该值与签入的值不同。closure_boi
val
main
- Rust 不允许其他线程在没有同步的情况下修改第一个线程正在读取的值,因为这会构成数据竞争。解决方法是使用类似锁
Mutex
或类似AtomicBool
.
考虑到上述情况,这里是编译和工作的代码的修改(操场):
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;
trait Surf {
fn will_be_called_after_two_seconds(&mut self);
}
struct SurfingDog<'a>(&'a Mutex<bool>);
impl<'a> Surf for SurfingDog<'a> {
fn will_be_called_after_two_seconds(&mut self) {
let mut state = self.0.lock().unwrap();
*state = true;
}
}
fn closure_boi<S: Surf>(mut x: impl FnMut() -> S) {
let mut surfer = x();
sleep(Duration::from_secs(2));
surfer.will_be_called_after_two_seconds();
sleep(Duration::from_secs(10)); // keep running
}
fn main() {
let val = Arc::new(Mutex::new(false));
std::thread::spawn({
let val = Arc::clone(&val);
move || {
closure_boi(|| SurfingDog(&*val));
}
});
sleep(Duration::from_secs(5));
assert_eq!(true, *val.lock().unwrap());
}
推荐阅读
- c# - EF Core 查询 Where 子句是一个集合?
- c++ - QLabel 像视频一样显示图像
- c# - 声明非空字符串时,C# 是否隐式分配空字符串?
- pywin32 - 无法通过pywinauto点击树元素
- excel - VLOOKUP 将两个表合并为一个
- spring - 如何使用 grails 知道响应拦截器中有效负载的大小
- javascript - 在 Express.js 应用程序中从 index.js 文件中排除默认路由
- r - 如何使用 R 中的 `openxlsx` 包在单元格范围周围应用粗边框
- angular - 如何在 angular-cli.json 中获取 serviceWorker 标志?
- php - 由于 htaccess 中的类似规则,RewriteRule 未执行