如何永久移动闭包 [英] How to move closures forever
问题描述
我正在设计一个为我运行闭包的小结构,我可以将它们设置为停止:
pub fn run(&self, f: Box) {让 should_continue = self.should_continue.clone();self.run_thread = Some(std::thread::spawn(move || {而 should_continue.load(Ordering::Relaxed) {//f 应该运行得很快,所以 `should_continue` 被频繁读取F();}}));}
如您所见,我将 Fn
传递到一个框中,这给了我一个错误,提示 Box 无法在线程之间共享.实际上,一旦我将 fn 传递给这个函数 run
,我就不关心它,所以我想将闭包移动到这个函数中,因为我不会再使用它了.我不能将 Fn
标记为发送,因为我要实际传递的 f
没有实现 Send
.
那么,我如何才能完全移动闭包?
//把这个闭包移到run里面self.run(||{});
拥有可构建的复制案例而不是具有随机未提供依赖项的代码很有用 所以这是我对你的代码的理解.
我得到的错误是dyn Fn
不能在线程之间发送,这与共享非常不同:虽然有很多不能在线程之间共享(Sync
)的东西(它们一次只能从一个线程使用)还有一些东西必须保留在它们的原始线程上整天.例如,Rc
不是 Send
,因为它不是线程安全的引用计数指针,将 Rc
发送到不同的线程会破坏它的保证,因此这是不允许的.
dyn Fn
是不透明的,除了可以多次调用之外,并不能真正保证它在内部做什么.因此,就编译器而言,它可以关闭不是 Send
的东西(例如对 !Sync
类型的引用,或 Rc
, ...),这意味着编译器假定 Fn
也不是 Send
.
解决方案很简单:只需定义f:Box
,这样在run
中你就可以保证函数实际上可以,在线程之间发送;如果run
的调用者尝试发送无法发送的函数,则会收到错误消息.
演示>
run_ok
使用一个简单的闭包,发送它没有问题.run_not_ok
关闭 Rc
,因此该函数不会编译(只需取消注释即可查看).run_ok2
与 run_not_ok
的功能相同,使用 Arc
而不是 Rc
,并且编译良好.
I'm designing a little struct that runs closures for me and I can set them to stop:
pub fn run(&self, f: Box<dyn Fn()>) {
let should_continue = self.should_continue.clone();
self.run_thread = Some(std::thread::spawn(move || {
while should_continue.load(Ordering::Relaxed) {
//f should run fast so `should_continue` is readed frequently
f();
}
}));
}
as you can see, I'm passing Fn
in a box, which gives me an error about Box not being shareable between threads. Actually, I don't care about fn once I pass it to this function run
, so I wanted to move the closure to this function, since I'll not use it anymore. I cannot mark Fn
as send because the f
that I'm gonna actually pass does not implement Send
.
So, how can I move a closure completely?
//move this closure to inside of run
self.run(||{});
Having a buildable reproduction case rather than code with random unprovided dependencies is useful so here's what I understand of your code.
The error I get is that the dyn Fn
can not be sent between threads which is very different than shared: while there are many things which can not be shared (Sync
) between threads (they can only be used from one thread at a time) there are also things which must remain on their original thread at all time. Rc
for instance, is not Send
, because it's not a thread-safe reference-counted pointer sending an Rc
to a different thread would break its guarantees, therefore that's not allowed.
dyn Fn
is opaque and offers no real guarantee as to what it's doing internally except for, well, being callable multiple times. So as far as the compiler is concerned it could close over something which isn't Send
(e.g. a reference to a !Sync
type, or an Rc
, ...), which means the compiler assumes the Fn
isn't Send
either.
The solution is simple: just define f: Box<dyn Fn() + Send>
, this way within run
you guarantee that the function can, in fact, be sent between threads; and the caller to run
will get an error if they're trying to send a function which can not be sent.
run_ok
uses a trivial closure, there is no issue with sending it over. run_not_ok
closes over an Rc
, and the function therefore doesn't compile (just uncomment it to see). run_ok2
is the same function as run_not_ok
using an Arc
instead of the Rc
, and compiles fine.
这篇关于如何永久移动闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!