rust 在结构中传递Mutex和MutexGuard

krcsximq  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(142)

bounty已结束。此问题的答案有资格获得+50声望奖励。赏金宽限期19小时后结束。Matt Joiner希望引起更多的注意这个问题。

我试图返回一个包含共享互斥体引用的结构:

  1. struct Test<'a> {
  2. mutex: Arc<Mutex<()>>,
  3. guard: &'a MutexGuard<'a, ()>,
  4. }
  5. impl<'a> Test<'a> {
  6. pub fn new() -> Self {
  7. let mutex = Arc::new(Mutex::new(()));
  8. let guard = &mutex.lock().unwrap();
  9. Self {
  10. mutex,
  11. guard,
  12. }
  13. }
  14. }

寿命似乎是正确的:互斥体至少在Test的生存期内存在,因此MutexGuard没有对互斥体的延迟引用。但是Rust会出错。如何向Rust解释mutex字段的生存期足够长,可以让guard正常工作?

  1. cannot return value referencing local variable `mutex`
  2. returns a value referencing data owned by the current function

顺便说一句,我试图创建一个“多互斥”-一组密钥互斥(如HashMap),以阻止下载一个文件的名称是在散列表(因为它已经在下载)。

tmb3ates

tmb3ates1#

这是不可能的,而且你写的东西很可能不是你想做的。
互斥锁守卫的目标是在互斥锁被丢弃时将其解锁。如果你把一个生命周期的守卫绑定到互斥体本身,你就是说它永远不会被丢弃,因此互斥体将永远被锁定。
不管怎样,你为什么需要警卫的资料?通常你不会在意,你只是希望它保持锁,只要它被引用。
也许你想这么做?你需要更多的上下文来看看这是否正是你想做的:D

  1. use std::sync::{Arc, Mutex, MutexGuard};
  2. struct Test {
  3. mutex: Arc<Mutex<()>>,
  4. }
  5. impl Test {
  6. pub fn new() -> Self {
  7. let mutex = Arc::new(Mutex::new(()));
  8. Self { mutex }
  9. }
  10. pub fn try_download(&self) -> Option<MutexGuard<()>> {
  11. let guard = self.mutex.try_lock();
  12. if guard.is_ok() {
  13. println!("Download started!");
  14. return guard.ok();
  15. } else {
  16. println!("Cannot download since it's already downloading");
  17. return None;
  18. }
  19. }
  20. }
  21. fn main() {
  22. let test = Test::new();
  23. // This could be kept alive like you said in an hashmap, so the guard is not dropped
  24. // v
  25. let a = test.try_download(); // Download started!
  26. let b = test.try_download(); // Cannot download since it's already downloading
  27. }

为什么你的代码不工作

实际上有两个问题
1.对未知堆栈空间的引用(segfault!)

  1. impl<'a> Test<'a> {
  2. pub fn new() -> Self {
  3. let mutex = Arc::new(Mutex::new(()));
  4. // ^
  5. // This reference has the lifetime of mutex
  6. // v
  7. let guard = &mutex.lock().unwrap();
  8. Self {
  9. mutex, // mutex is moved here, so guard points to something which is at this time
  10. // unknown. This can be known only after the new stack frame is built
  11. guard,
  12. }
  13. }
  14. }

1.互斥锁到底存储在哪里?在你的例子中,它位于函数new的堆栈框架上。然后将指向它的指针存储在结构中并返回它。通过返回,你也删除了堆栈,那么指针指向哪里呢?(segfault!)

  1. impl<'a> Test<'a> {
  2. pub fn new() -> Self {
  3. let mutex = Arc::new(Mutex::new(()));
  4. // MutexGuard is created here and put in the stack dropped when the function exits.
  5. // v
  6. let guard = &mutex.lock().unwrap();
  7. Self { mutex, guard }
  8. }
  9. }
展开查看全部

相关问题