gpt4 book ai didi

rust - 如何在Rust中创建单线程单例?

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

我目前正在尝试将C库包装在具有一些要求的rust中。 C库只能在单个线程上运行,并且只能在同一线程上初始化/清理一次。我想要类似以下内容的东西。

extern "C" {
fn init_lib() -> *mut c_void;
fn cleanup_lib(ctx: *mut c_void);
}

// This line doesn't work.
static mut CTX: Option<(ThreadId, Rc<Context>)> = None;

struct Context(*mut c_void);

impl Context {
fn acquire() -> Result<Rc<Context>, Error> {
// If CTX has a reference on the current thread, clone and return it.
// Otherwise initialize the library and set CTX.
}
}

impl Drop for Context {
fn drop(&mut self) {
unsafe { cleanup_lib(self.0); }
}
}
任何人都有实现这种目标的好方法吗?我尝试提出的每个解决方案都涉及创建Mutex/Arc,并使不需要的 Context类型 SendSync成为我希望保持单线程的类型。

最佳答案

我想出的一个可行解决方案是仅对引用进行计数,完全消除对Rc的需要。

#![feature(once_cell)]

use std::{error::Error, ffi::c_void, fmt, lazy::SyncLazy, sync::Mutex, thread::ThreadId};

extern "C" {
fn init_lib() -> *mut c_void;
fn cleanup_lib(ctx: *mut c_void);
}

#[derive(Debug)]
pub enum ContextError {
InitOnOtherThread,
}

impl fmt::Display for ContextError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ContextError::InitOnOtherThread => {
write!(f, "Context already initialized on a different thread")
}
}
}
}

impl Error for ContextError {}

struct StaticPtr(*mut c_void);
unsafe impl Send for StaticPtr {}

static CTX: SyncLazy<Mutex<Option<(ThreadId, usize, StaticPtr)>>> =
SyncLazy::new(|| Mutex::new(None));

pub struct Context(*mut c_void);

impl Context {
pub fn acquire() -> Result<Context, ContextError> {
let mut ctx = CTX.lock().unwrap();
if let Some((id, ref_count, ptr)) = ctx.as_mut() {
if *id == std::thread::current().id() {
*ref_count += 1;
return Ok(Context(ptr.0));
}

Err(ContextError::InitOnOtherThread)
} else {
let ptr = unsafe { init_lib() };
*ctx = Some((std::thread::current().id(), 1, StaticPtr(ptr)));
Ok(Context(ptr))
}
}
}

impl Drop for Context {
fn drop(&mut self) {
let mut ctx = CTX.lock().unwrap();
let (_, ref_count, ptr) = ctx.as_mut().unwrap();
*ref_count -= 1;
if *ref_count == 0 {
unsafe {
cleanup_lib(ptr.0);
}
*ctx = None;
}
}
}

关于rust - 如何在Rust中创建单线程单例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66509432/

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