在新线程中从共享库执行asyncronus函数(Rust)

影子代码

从他的Rust FFI指南中遵循了Michael-F-Bryan的“动态加载和插件”一章,但是我将插件存储在HashMapHashMap<&'static str, Box<dyn Plugin>)中,而不是在a中存储,Vec以便可以Plugin单独调用函数

我希望插件使用自己的循环定义一个异步函数,该循环使用通道(stdtokio与应用程序的主要部分进行通信

async多亏了async_trait板条箱,解决了无法在traits中使用函数这一事实很容易,但是我现在面临的问题是,我无法使用该模块生成新线程,因为新线程可能会超过PluginManager

我试图在没有动态模块的锈迹重现的操场上重新创建它,在这里我面临着同样的错误(注意:这不包括任何形式的通道通信)

与第一个错误不同,我无法为第二个错误重新创建一个锈蚀操场(因为它在运行时发生)。我没有使用新的线程,而是使用tokio的事件循环来处理async函数。这在沙盒中有效,但在使用共享库作为插件时无效。在运行时,它抛出:

thread '<unnamed>' panicked at 'there is no timer running, must be called from the context of Tokio runtime', /home/admin/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.0.1/src/time/driver/handle.rs:50:18

如果有人知道解决此问题的方法,甚至遇到相同的问题,那么最好与我分享这些信息,因为我已经做了很多尝试,但没有任何对我有利的方法。

有害的

您已经认识到了问题:对拥有的对象的引用PluginManager已移至正在生成的Future中,因此可能在拥有的线程之外的另一个线程上运行PluginManager编译器无法知道将来不会超过PluginManager

有许多可能的解决方案,例如:

  • 将插件实例存储在中Arc<Box<T>>,以便在运行时对它们进行引用计数。然后,即使插件管理器的寿命不长于您生成的期货,也没关系

  • 使PluginManager一个不变的静态单例

在这种情况下,我怀疑您希望PluginManager成为单例。您可以通过用new构造get延迟实例并返回引用方法来代替构造函数来做到这一点:

use once_cell::sync::Lazy;

impl PluginManager {

    pub fn get() -> &'static Self {
        static PLUGINMANAGER: Lazy<PluginManager> = Lazy::new(|| {
            let mut mgr = PluginManager {
                plugins: HashMap::new()
            };
            mgr.load_plugins();
            mgr
        });
        &PLUGINMANAGER
    }
// ...
}

请注意,此惰性构造函数会完全初始化静态实例,包括加载插件。

它使用once_cell::sync::Lazyafter_cell板条箱。该功能也可在每晚的std中使用,因此最终将成为标准库的一部分。

spawn_plugins函数需要稍作更改以指定它需要一个静态self:

pub async fn spawn_plugins(&'static self) {
//...

最后,您的主要功能变为:

async fn main() {
    let mgr = PluginManager::get();
    mgr.spawn_plugins().await;
}

游乐场链接

关于另一个问题,这是一个单独的问题-如果您一次发布一个问题,则堆栈溢出效果最好。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章