基于eBPF的procstat软件定位软件死锁

在现代计算机系统中,多线程程序比较普遍,死锁是发生在多线程程序中一个棘手的问题。当两个或多个线程相互等待对方释放资源时,程序便陷入了无限期的等待状态,从而导致程序无法继续执行。为了有效地检测这种死锁问题,本文将介绍一种基于eBPF(Extended Berkeley Packet Filter)的性能监测软件procstat,该软件可以深入监测到程序内部的运行状态,帮助我们准确定位死锁问题。

procstat软件简介

procstat是一款基于eBPF的监控工具软件,运行在Linux平台,主要用于跟踪目标程序的运行状态,并报告异常指标,是分析程序性能问题的一大利器。同时,procstat也可用于检测和定位C/C++多线程程序中的死锁问题。该软件通过eBPF技术,可以深入到标准库内部,监控线程的锁定和解锁行为,实时捕捉程序的运行状态。当检测到死锁情况时,procstat会在日志中输出详细的错误信息,帮助开发者快速定位问题根源。接下来我们将通过一个小实验来展示一下procstat软件是如何定位程序死锁的。
此软件可以在以下链接中下载到,并提供免费试用,后续还会有版本更新迭代,使用时需要能连互联网环境。
CSDN下载链接
Github下载链接

死锁示例代码

#include <iostream>
#include <mutex>
#include <thread>
std::mutex mtx1;
std::mutex mtx2;
std::mutex mtx3;
void func1()
{
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        std::lock_guard<std::mutex> lock(mtx1);
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        std::lock_guard<std::mutex> lock1(mtx2);
    }
}
void func2()
{
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        std::lock_guard<std::mutex> lock(mtx2);
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        std::lock_guard<std::mutex> lock1(mtx3);
    }
}
void func3()
{
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        bool is_lock = mtx3.try_lock();
        std::this_thread::sleep_for(std::chrono::milliseconds(15000));
        std::lock_guard<std::mutex> lock(mtx1);

        if (is_lock) {
            mtx3.unlock();
        }
    }
}

int main()
{
    std::thread t1(&func1);
    std::thread t2(&func2);
    std::thread t3(&func3);
    t1.join();
    t2.join();
    return 0;
}

在以上代码中,创建了3个子线程func1、func2、func3和3个互斥锁mtx1、mtx2、mtx3,这三个线程分别持有这三个锁,持有成功后会再尝试持有其他线程所持有的锁,最终形成一个环,造成死锁。

使用procstat检测死锁

编译并启动上述代码后,使用procstat软件来监控该程序并检测死锁。本实验中,编译后的程序名为deadlock,我们可以通过以下命令启动procstat进行监控:sh start.sh -p 进程号。其中,<进程号>是正在运行的deadlock程序的进程ID。

运行程序

[root@VM-8-2-centos deadlock]# ./deadlock &
[1] 3967882
[root@VM-8-2-centos deadlock]# cd -
/root/work_dir/procstat/bin
[root@VM-8-2-centos bin]# sh start.sh -p 3967882
Start Loading...!
Start Stating...!

启动监控后(输出“Start Stating…!”后就已开始监控了),procstat会持续监控该程序的运行状态,并在日志中记录时间较长的锁定和解锁操作(时长可配置)。

查看procstat软件日志

接下来我们查询procstat的日志信息,并搜索LOCK关键字。
死锁检测结果从结果图中可看出,被监控的deadlock进程产生了死锁,我们分析一下日志输出的内容可知,此进程中各线程的加锁状态如下:
(1)线程1(tid = 3969986)持有了锁(0x604160),请求锁(0x6040e0)
(2)线程2(tid = 3969984)持有了锁(0x6040e0),请求锁(0x604120)
(3)线程3(tid = 3969985)持有了锁(0x604120),请求锁(0x604160)
通过分析可知,这三个线程都请求多个锁,形成了一个环状的等待状态,造成了死锁。

eBPF的优势

基于eBPF的procstat软件有以下几个显著优势:

  1. 深入监控:eBPF可以深入到标准库内部,监控细粒度的锁操作,提供更加精确的监控数据;
  2. 低开销:eBPF程序在监测一些异常事件时(如本文的死锁检测),开销极低,不会显著影响被监控程序的性能。
  3. 实时性:eBPF程序可以实时捕捉系统调用和事件,确保死锁问题能够被及时发现和记录。

总结

死锁是多线程编程中常见且难以调试的问题。基于eBPF的procstat软件通过实时监控程序的锁操作,提供了一种高效且精确的死锁检测方法。通过深入标准库内部的监控,procstat能够帮助开发者快速定位死锁问题,提升程序的稳定性和可靠性。
procstat软件还可以监测很多的程序异常状态,随着eBPF技术的不断发展和procstat软件不断的迭代,希望能够帮助大家定位程序的性能问题和异常问题,进一步提升对软件和操作系统的监控能力,欢迎大家试用,有问题请私信我,共同学习、交流,共同进步!

  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PerfMan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值