中文
注册
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助

Rust进程卡死

定位思路

死锁发生于两个及以上的线程互相等待对方采取行动,由于资源的锁定,没有线程能够获取所需资源,从而导致无限挂起。表现为程序会一直处于运行状态无法结束。定位思路如图1所示。

图1 Rust进程卡死定位思路
  1. 使用top命令查看相关进程仍在运行,程序长时间运行,并且没有新的打印日志。单核CPU出现100%或者所有cpu占用为0%状态,确认是进程卡死。
  2. 根据业务逻辑,找到怀疑卡死的线程,运行GDB attach调试。
  3. 分析堆栈信息及业务逻辑,找出卡死原因。
  4. 修改代码,重新编译进行验证。
  5. 若问题解决,则确认修改,合入原代码。
  6. 若问题未解决,增加定位信息,重新编译运行。

案例:管道通信导致系统卡死

问题现象

在Rust中,线程通信一般依靠两种方式,管道通信和互斥锁管理。由于Rust特殊的所有权机制,有效的避免了大部分因数据竞争而导致的死锁问题。但对死锁问题依旧没有彻底解决。在互斥锁导致死锁的情况下,GDB调用栈会显示线程处于__lll_lock_wait状态,现象与问题定位过程与C/C++进程卡死一致。而遇到管道通信导致死锁,定位方法如下。

定位过程:

  1. 运行过程中,发现运行时间过长,且通过top命令查看CPU占用为0,怀疑为进程卡死。
  2. 运行cargo build进行编译,其生成的可执行文件存在于“./target/debug/”目录下,使用GDB运行。GDB使用说明请参见GDB
     gdb ./target/debug/FileCyber
    (gdb) r
    
  3. 遇到死锁时,使用ctrl c命令中止,并使用info threads命令查看线程。

  4. 如果有线程存在pthread_mutex_lock,则需要查看其对应的线程。但在现在的状态下,thread 1在进行pthread_join,即在等待其他线程的运行结束,根据代码逻辑,此时进程在等待t1任务的完成。选择需要重点查看其他的线程:thread 4 和thread 2。

    查看backtrace:bt

    thread 4 的TID为33928,thread 2 的TID为33926。

  5. 分析frame。

    根据bt信息查看代码,发现是由于t3未收到消息导致死锁,查看对应的逻辑之后,修改代码,死锁问题不再复现。

    在修改Rust第三方的代码时,注意使用上文的patch.crates-io标签,让Rust代码依赖本地的被修改的第三方库。