gpt4 book ai didi

multithreading - 在将包含Arc的self移到新线程中时,为什么会出现 “Sync is not satisfied”错误?

转载 作者:行者123 更新时间:2023-12-03 11:31:32 25 4
gpt4 key购买 nike

我有一个包含Arc<Receiver<f32>>的结构,我试图添加一个获取self所有权的方法,并将所有权移到新线程中并启动它。但是,我得到了错误

error[E0277]: the trait bound `std::sync::mpsc::Receiver<f32>: std::marker::Sync` is not satisfied
--> src/main.rs:19:9
|
19 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<f32>` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<f32>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::mpsc::Receiver<f32>>`
= note: required because it appears within the type `Foo`
= note: required because it appears within the type `[closure@src/main.rs:19:23: 22:10 self:Foo]`
= note: required by `std::thread::spawn`

如果我更改结构以改为保留 Arc<i32>或仅保留 Receiver<f32>,则它将编译,但不使用 Arc<Receiver<f32>>。这是如何运作的?该错误对我而言没有任何意义,因为我没有尝试在线程之间共享它(我正在移动它,而不是克隆它)。

这是完整的代码:
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::thread;

pub struct Foo {
receiver: Arc<Receiver<f32>>,
}

impl Foo {
pub fn new() -> (Foo, Sender<f32>) {
let (sender, receiver) = channel::<f32>();
let sink = Foo {
receiver: Arc::new(receiver),
};
(sink, sender)
}

pub fn run_thread(self) -> thread::JoinHandle<()> {
thread::spawn(move || {
println!("Thread spawned by 'run_thread'");
self.run(); // <- This line gives the error
})
}

fn run(mut self) {
println!("Executing 'run'")
}
}

fn main() {
let (example, sender) = Foo::new();
let handle = example.run_thread();
handle.join();
}

最佳答案

How does this work?



让我们再次检查 thread::spawn 的要求:
pub fn spawn<F, T>(f: F) -> JoinHandle<T> 
where
F: FnOnce() -> T,
F: Send + 'static, // <-- this line is important for us
T: Send + 'static,

由于 Foo包含 Arc<Receiver<_>>,因此让我们检查 Arc implements Send 以及如何:
impl<T> Send for Arc<T> 
where
T: Send + Sync + ?Sized,

因此,如果 Arc<T>实现 SendT,则 Send实现 Sync。而 Receiver implements Send it does not implement Sync

那么,为什么 ArcT有如此强烈的要求? T还必须实现 Send,因为 Arc可以充当容器;如果您只能在 Send中隐藏未实现 Arc的内容,请将其发送到另一个线程并在其中解压缩...可能会发生不好的事情。有趣的部分是看看 T为什么还必须实现 Sync,这显然也是您正在努力的部分:

The error doesn't make sense to me as I'm not trying to share it between threads (I'm moving it, not cloning it).



编译器无法知道 Arc中的 Foo实际上并未共享。考虑一下您是否稍后将 #[derive(Clone)]添加到 Foo(这可能没有问题):
fn main() {
let (example, sender) = Foo::new();
let clone = example.clone();
let handle = example.run_thread();
clone.run();
// oopsie, now the same `Receiver` is used from two threads!

handle.join();
}

在上面的示例中,线程之间仅共享一个 Receiver。这是不好的,因为 Receiver没有实现 Sync!

对我来说,这段代码提出了一个问题:为什么首先要使用 Arc?正如您所注意到的,没有 Arc,它可以正常工作而没有问题:您清楚地声明 FooReceiver的唯一所有者。而且,如果您仍然“不尝试共享[接收者]”,那么拥有多个所有者是没有意义的。

关于multithreading - 在将包含Arc的self移到新线程中时,为什么会出现 “Sync is not satisfied”错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63094640/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com