如何永久移动闭包 [英] How to move closures forever

查看:26
本文介绍了如何永久移动闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设计一个为我运行闭包的小结构,我可以将它们设置为停止:

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_ok2run_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.

demo

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆