【发布时间】:2016-04-01 14:47:40
【问题描述】:
我正在为 C 库编写一个包装器/FFI,该库需要在主线程中进行全局初始化调用以及用于销毁。
这是我目前的处理方式:
struct App;
impl App {
fn init() -> Self {
unsafe { ffi::InitializeMyCLib(); }
App
}
}
impl Drop for App {
fn drop(&mut self) {
unsafe { ffi::DestroyMyCLib(); }
}
}
可以这样使用:
fn main() {
let _init_ = App::init();
// ...
}
这很好用,但感觉就像一个 hack,将这些调用绑定到一个不必要的结构的生命周期。在 finally (Java) 或 at_exit (Ruby) 块中使用析构函数在理论上似乎更合适。
在 Rust 中是否有更优雅的方式来做到这一点?
编辑
是否可以/安全地使用这种设置(使用lazy_static crate),而不是我上面的第二个块:
lazy_static! {
static ref APP: App = App::new();
}
是否保证此引用在任何其他代码之前被初始化并在退出时被销毁?在库中使用lazy_static 是不好的做法吗?
这也将使通过这一结构访问 FFI 变得更加容易,因为我不必费心传递对实例化结构的引用(在我的原始示例中称为 _init_)。
这在某些方面也会使其更安全,因为我可以将 App 结构的默认构造函数设为私有。
【问题讨论】:
-
旁注:根据您希望包装器的安全程度,您应该使
init函数不安全(因为没有人可能会多次调用它),并实现所有需要 clib 的函数被初始化为App对象上的方法。这样,没有人可以在没有初始化的情况下调用这些函数。您还可以将其实现为某种引用计数单例,以使其安全初始化。这是对 Java 和 Ruby 的一大胜利,因为您可以在没有初始化 lib 的情况下调用函数 -
在主线程中——你确定它必须是主线程吗?它可以是任何线程,只要它在使用前被初始化?
-
@ker,感谢您的评论。我没有这样想过(通过
App结构进行所有访问,但这是有道理的。我将不得不考虑这是否适用于我的情况。 -
@Shepmaster,感谢您的评论。 C 库是 GraphicsMagick,我只是参考文档:
This function should be invoked in the primary (original) thread of the application's process。我是一名主要来自 Ruby 的 Rust 初学者,所以我并不真正了解线程使用方面的“必须”。
标签: rust