首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何协调Rust Mutex和(C)调用者提供的锁定机制?

如何协调Rust Mutex和(C)调用者提供的锁定机制?
EN

Stack Overflow用户
提问于 2021-09-27 17:03:57
回答 1查看 102关注 0票数 4

我正在用Rust编写一个PKCS#11库,我遇到了一些问题,比如如何使调用者提供的锁定机制(如CreateMutex、DestroyMutex、LockMutex、UnlockMutex )与Rust的互斥锁实现相协调。

当然,C中的Mutexes并不依赖于数据。它们只是在一个段上设置一个锁,程序员负责创建/销毁和锁定/解锁互斥锁。然而,Rust确实将数据绑定到互斥锁本身。

我如何协调这两种情况:当调用程序提供锁定机制(不绑定到数据和手动创建/锁定/解锁/销毁)时,没有提供锁定机制并使用Rust锁定(绑定到数据和MutexGuard以及互斥锁的作用域删除/解锁)?

我是否应该使用parking_lot::Mutex和raw_lock/raw_unlock来使模式相似,例如不绑定到数据?

EN

回答 1

Stack Overflow用户

发布于 2021-09-28 01:11:23

这是我的解决方案;它并不美观,但它很有效,并且通过了miri测试。一般的想法是我们为该互斥锁捆绑一个Mutex<()>和一个可选的MutexGuard。我没有添加正确的错误处理或命名来匹配标准。

结构:

代码语言:javascript
复制
struct MutexContainer {
    mutex: Mutex<()>,
    guard: Cell<Option<MutexGuard<'static, ()>>>,
}
pub struct OpaqueMutex {
    _data: [usize;0],
}

请注意,OpaqueMutex只是一个不透明的句柄,以避免泄漏MutexContainer的内部,这是ffi期间的最佳实践。这种设计的关键之处在于,如果结构有一个守卫,它就不能移动。

创建互斥锁:

代码语言:javascript
复制
pub unsafe extern "C" fn create_mutex(mutex: *mut *mut OpaqueMutex) -> libc::c_ulong {
    *mutex = Box::into_raw(Box::new(
        MutexContainer {
            mutex: Mutex::new(()),
            guard: Cell::new(None),
        },
    ))
    .cast();
    0
}

这里没有什么特别的事情,只是泄漏了堆上的互斥锁。

互斥锁:

代码语言:javascript
复制
pub unsafe extern "C" fn lock_mutex(mutex: *mut OpaqueMutex) -> libc::c_ulong {
    let container:&MutexContainer = &*mutex.cast();
    let lock:MutexGuard<'static, _> = mem::transmute(container.mutex.lock().unwrap());
    container.guard.set(Some(lock));
    0
}

在这里,我使用mem::transmute来延长锁的生命周期并存储结果。transmute是安全的,因为我们确保不移动它的父互斥锁,也不让它在这里或其他地方超过互斥锁。互斥锁将保持锁定状态,直到解除守卫。

互斥解锁:

代码语言:javascript
复制
pub unsafe extern "C" fn unlock_mutex(mutex: *mut OpaqueMutex) -> c_ulong{
    let container:&MutexContainer = &*mutex.cast();
    if container.mutex.try_lock().is_ok(){
        return !0; //can't unlock an unlocked mutex
    } else {
        container.guard.set(None);
    }
    0
}

在这里,我们使用非阻塞try_lock来确定互斥锁是否被锁定。如果try_lock成功,这意味着互斥锁被解锁,我们返回一个错误。否则,我们通过用None覆盖它来放弃保护。

互斥锁丢弃:

代码语言:javascript
复制
pub unsafe extern "C" fn drop_mutex(mutex: *mut OpaqueMutex) -> c_ulong{
    unlock_mutex(mutex);
    drop(Box::from_raw(mutex.cast::<MutexContainer>()));
    0
}

在这里,我们确保互斥锁被解锁,以防止守卫的悬空引用,然后通过重新装箱指针来回收内存。

Full playground link plus test harness.

免责声明:虽然这段代码通过了miri,但它还远远没有准备好投入生产:基本上没有错误处理。您应该确保健壮地处理错误,并进行健全性检查(如null和对齐检查),尤其是在实现加密库的情况下。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69350600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档