我使用的特征不是针对多线程(草书)设计的。
现在,虽然它使用了多线程,但它将位于互斥之后,所以它不能同时在两个线程上使用。
铁锈试图保护我免受什么危害,我能做些什么呢?
作为示例参考,我的示例代码是:
extern crate cursive;
use cursive::Cursive;
use std::thread;
use std::sync::{Mutex,Arc};
fn main() {
let mut siv = Arc::new(Mutex::new(Cursive::default()));
let copy_siv = siv.clone();
thread::spawn(move || {
let mut new_siv = copy_siv.lock().unwrap();
});
(*(siv.lock().unwrap())).run();
}编译器在thread::spawn上抱怨
Error[E0277]: `(dyn cursive::traits::View + 'static)` cannot be sent between threads safely
--> src/main.rs:16:5
|
16 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `(dyn cursive::traits::View + 'static)` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `(dyn cursive::traits::View + 'static)`发布于 2018-10-18 13:40:14
什么是铁锈试图保护我不受...
您在线程之间发送的内容包含一个dyn cursive::traits::View特征对象。此特征对象不是Send。它需要是Send,因为通过将它放在Arc中,您不能再预测哪个线程将负责销毁它,因此在线程之间转移所有权必须是安全的。
...对此我能做些什么吗?
您还没有提供足够的上下文来确定,但很可能不是。
您可以尝试使用简单的借用参考(外加一个支持作用域线程的线程库),但我不能说这是否适用于您。
为什么互斥锁不能同步?这不就是Mutex的意义所在吗?
不是的。它不能让某些东西变得线程安全,因为它已经不是线程安全的。Mutex只管理对某个值的独占访问,它不会确保从不同线程进行的访问是安全的。唯一能使类型成为线程安全的就是所讨论的类型。
猜测:这个库不需要线程安全,因此Arc不能假定它是线程安全的,所以它拒绝编译。
发布于 2018-10-19 06:30:15
我不知道你的实际代码是什么。但下面的示例复制了您遇到的确切错误:
use std::thread;
use std::sync::{Mutex,Arc};
struct Cursive;
impl Default for Cursive {
fn default() -> Self {
Cursive
}
}
trait View{
fn run(&self);
}
impl View for Cursive{
fn run(&self){}
}
fn main() {
let mut siv:Arc<Mutex<dyn View>> = Arc::new(Mutex::new(Cursive::default()));
let copy_siv = siv.clone();
thread::spawn(move || {
let mut new_siv = copy_siv.lock().unwrap();
});
(*(siv.lock().unwrap())).run();
}您可以在playground中尝试。错误消息:
error[E0277]: `dyn View` cannot be sent between threads safely
--> src/main.rs:21:5
|
21 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `dyn View` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `dyn View`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<dyn View>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<dyn View>>`
= note: required because it appears within the type `[closure@src/main.rs:21:19: 23:6 copy_siv:std::sync::Arc<std::sync::Mutex<dyn View>>]`
= note: required by `std::thread::spawn`分析和解决方案
错误消息向有经验的用户解释了一切。对于那些刚接触该语言的人来说,siv是一个引用计数、互斥保护的特征对象。这个对象只知道是一个View,编译器没有证据表明它是否是Send。但是,为了让代码正常工作,
Arc<Mutex<T>>必须为Send,因为您要将此类内容发送到另一个线程;Therefore:Mutex<T>必须为Send和Sync,因为Arc要求引用计数对象为Send和Sync。Therefore:T必须为Send,因为同一对象将在没有任何进一步保护的情况下在不同的线程中被访问。所以,这段代码不能工作。解决方案是
let mut siv:Arc<Mutex<dyn View + Send>> = ...你可以自己尝试一下!
Mutex<T>: Send + Sync需要T: Send
要了解原因,首先要问一个问题: what cannot be Send
一个例子是对具有内部易变性的事物的引用不能是Send。因为如果是这样的话,人们可以通过不同线程中的内部易变性来改变事物,从而导致数据竞争。
现在假设你有一个Mutex<&Cell<T>>,因为受保护的东西只是一个引用,而不是Cell本身,Cell本身可能仍然是不受保护的。因此,当您调用lock().set()时,编译器无法得出结论,不存在导致数据争用的风险。因此编译器会从Send中阻止它。
如果我不得不...
因此,我们看到&Cell<T>不是Send,所以即使它在Mutex中受到保护,我们仍然不能在另一个线程中使用它。那我们该怎么办呢?
这个问题实际上并不新鲜。几乎所有的UI都有相同的问题: UI组件是在UI线程中创建的,因此您不能在任何其他线程中访问它们。相反,您必须安排一个例程在UI线程中运行,并让UI线程访问组件。
在其他语言(.NET、Java...)中无法做到这一点。在最好的情况下会抛出异常,在最坏的情况下会导致未定义的行为。再一次,Rust在没有特殊处理的情况下将这种冲突转化为编译错误(&Cell<T>与UI无关),这真的很好!
因此,如果这是您想要做的,那么您必须执行相同的操作:仅在UI线程中访问视图对象。如何做到这一点取决于您所使用的API。
https://stackoverflow.com/questions/52866447
复制相似问题