首页 > 编程问答 >在 Rust 多线程应用程序中锁定 Mutex 时发生死锁

在 Rust 多线程应用程序中锁定 Mutex 时发生死锁

时间:2024-05-30 14:13:11浏览次数:30  
标签:multithreading rust concurrency mutex deadlock

我正在开发一个 Rust 应用程序,其中有一个与 PacketManager 交互的 BusDevice。在多线程环境中尝试锁定一个 Mutex 时,我遇到了死锁。应用程序被卡在锁定 Mutex 的那一行,再也无法继续。

详细描述:

在我的 Rust 应用程序中,我有一个使用 PacketManager 发送确认数据包的 BusDevice。BusDevice 中的 send_ack 方法会生成一个新线程来处理确认,但在试图获取 PacketManager 的 Mutex 上的锁时似乎会挂起。

以下是我的 BusDevice 实现的相关部分:

use std::sync::{Arc, Mutex};

pub struct BusDevice {
    packet_manager:Arc<Mutex<PacketManager>>、
    // 其他字段...
}

impl BusDevice {
    pub fn send_ack(&self, dest: u8, seq: u8) {
        let packet_manager = Arc::clone(&self.packet_manager);

        std::thread::spawn(move || {
            让 pm = packet_manager.lock();
            匹配 pm {
                Ok(mut pm) => {
                    pm.send_ack(0, dest, seq);
                }
                Err(e) => {
                    println!("Failed to lock PacketManager: {:?}", e);
                }
            }
        })
        .join()
        .expect("Thread join failed");
    }
}

而 PacketManager 的结构如下:

use std::sync::{Arc, Mutex};
使用 serialport::TTYPort;

pub struct PacketManager {
    serial_port:Arc<Mutex<TTYPort>>、
    // 其他字段...
}

impl PacketManager {
    pub fn send_ack(&mut self, src: u8, dest: u8, seq: u8) { // 逻辑发送确认数据包。
        // 发送确认数据包的逻辑
    }
}
我所尝试的:

我已确保代码的其他部分不会长时间锁定。 我简化了 send_ack 方法以隔离问题,但问题依然存在。 我添加了打印语句来跟踪执行情况,结果证实应用程序在 packet_manager.lock() 处卡住了。

预期行为:

生成的线程应获取 PacketManager 上的锁,发送确认数据包,然后释放锁,而不会导致死锁。


代码中死锁的原因是在 send_ack 方法中使用了 thread::spawnjoin 的组合方式。

问题在于:

  1. send_ack 方法生成了一个新线程来处理确认数据包。
  2. 在新线程中,代码尝试获取 packet_manager 的锁。
  3. 同时,send_ack 方法调用 join 方法等待新线程结束。

这会导致死锁,因为:

  • 新线程持有 packet_manager 的锁,直到它完成发送确认数据包的操作。
  • 主线程(调用 send_ack 的线程)在 join 方法处等待新线程结束,而新线程需要先释放 packet_manager 的锁才能结束。

解决方案:

要解决这个问题,需要避免在持有锁的情况下等待线程结束。一种方法是将 join 操作移出 send_ack 方法:

use std::sync::{Arc, Mutex};

pub struct BusDevice {
    packet_manager: Arc<Mutex<PacketManager>>,
    // 其他字段...
}

impl BusDevice {
    pub fn send_ack(&self, dest: u8, seq: u8) {
        let packet_manager = Arc::clone(&self.packet_manager);

        std::thread::spawn(move || {
            let pm = packet_manager.lock();
            match pm {
                Ok(mut pm) => {
                    pm.send_ack(0, dest, seq);
                }
                Err(e) => {
                    println!("Failed to lock PacketManager: {:?}", e);
                }
            }
        });

        // 不要在这里调用 join()
    }
}

这样,主线程就不会阻塞等待新线程结束,从而避免了死锁。

其他建议:

  • 考虑使用通道(channel)在主线程和工作线程之间传递数据,而不是共享 Arc<Mutex<PacketManager>>。这样可以简化代码并提高性能。
  • 评估是否真的需要为每个确认数据包创建一个新线程。如果发送确认数据包的操作比较轻量级,可以考虑将这些操作放到一个线程池中执行。

标签:multithreading,rust,concurrency,mutex,deadlock
From: 78553162

相关文章

  • 【Rust】——使用消息在线程之间传递数据
    ......
  • geotrust通配符证书600元且赠送一个月
    GeoTrust作为国际知名的数字证书颁发机构,旗下有RapidSSL、QuickSSL等子品牌经营着各种类型的SSL数字证书,其中RapidSSL旗下的SSL数字证书都是入门级的,性价比高。审核速度也比较快,证书的适用范围也比较广泛。今天就随SSL盾小编了解GeotrustRapidSSL旗下的通配符SSL证书。1.Geot......
  • Rust Druid
     #![windows_subsystem="windows"]modcmd;usestd::time::Instant;uselibloader::libloading;usedruid::widget::prelude::*;usedruid::text::{FontDescriptor,FontFamily};usedruid::{AppLauncher,Color,Data,FileDialogOptions,FileSpec,Lens,Menu,......
  • Rust语言实现的去中心化AI网络节点
    一、概述去中心化和人工智能(AI)是两个极具潜力的发展方向。Gaia项目正是将这两者结合起来,创造了一个去中心化的AI网络节点。本文将深入探讨Gaia项目的技术细节,通过丰富的示例和详细描述,帮助读者全面理解并掌握该技术。二、什么是Gaia?Gaia是一个去中心化的人工智能网络,它旨......
  • Rust中的iter(), into_iter(), iter_mut()
    在Rust中,iter(),into_iter(),iter_mut()都是用于在集合类型上创建迭代器的方法。这三个方法各有不同,下面一一进行介绍。iter():iter()方法创建一个不可变的引用迭代器。当你只想读取集合中的元素,而不想改变它们或消耗集合时,应使用iter()。iter()返回的迭代器将生成集合中每......
  • X-CSV-Reader:一个使用Rust实现CSV命令行读取器
    ......
  • Rust腐蚀怎么用服务器一键开服联机教程
    1、进入控制面板首次登陆需要点击下方重置密码,如何再点击登录面板,点击后会跳转到登录页面,输入用户名和密码登录即可2、设置游戏端口由于腐蚀的设置需要三个端口,它们用于游戏端口(必须为首选端口),查询端口,RCON端口服务器创建时默认会获得一个首选端口,既为我们的游戏端口......
  • 基于three.js的Instanced Draw+LOD+Frustum Cull的改进实现
    大家好,本文在上文的基础上,优化了InstancedDraw+LOD+FrustumCull的性能,性能提升了3倍以上关键词:three.js、InstancedDraw、大场景、LOD、FrustumCull、优化、Web3D、WebGL、开源上文:three.js使用InstancedDraw+FrustumCull+LOD来渲染大场景(开源)相对于上文的改进点相对于......
  • Vitis HLS 学习笔记--控制驱动TLP-处理deadlock
    目录1.简介2.代码解析2.1HLSkernel代码2.2查看接口报告2.3TestBench2.4Dataflow报告3.Takeaways4.总结1.简介本文是对《HardwareAccelerationTutorials:FIFOSizingforPerformanceandAvoidingDeadlocks》实验内容的详细解释。首先需要了解,鉴于......
  • rustdesk域控灵活使用
    简介:rustdesk是一个非常好用的可以私域部署的远程协助软件,俗称远程桌面。好处就太多了。我的环境为了安全,全面封禁3389端口,封禁135,136,137,138,443。好在没要求服务器封禁,否则我的域控,MDT,都不能用了。环境又复杂,管理范围跨郑州,开封,虽说不远,还有开封灌汤包、驴肉汤、鲤鱼焙面………......