linux跟踪线程的方法:LWP和strace命令

简介: 摘要:在使用多线程程序时,有时会遇到程序功能异常的情况,而这种异常情况并不是每次都发生,很难模拟出来。这时就需要运用在程序运行时跟踪线程的手段,而linux系统的LWP和strace命令正是这种技术手段。

摘要:在使用多线程程序时,有时会遇到程序功能异常的情况,而这种异常情况并不是每次都发生,很难模拟出来。这时就需要运用在程序运行时跟踪线程的手段,而linux系统的LWP和strace命令正是这种技术手段。本文对LWP和strace命令做了简明扼要的介绍,并通过一个实例来说明如何运用。总而言之,LWP和strace的使用可以提高多线程程序的可维护性。

问题描述:

我们来看一个问题:程序tcp_client同时创建多个线程向同一个服务器发送数据,每个线程发送不同类型的数据,服务器接收数据后,可以通过界面查看到多个数据在刷新。程序运行一段时间后,突然出现只有某个类型的数据不刷新,其他数据刷新正常,但是服务端客户端程序都没有报错。这时我们该怎么办?

很明显,这时程序调试者需要知道不刷新线程的线程ID,然后通过某种手段查看该线程为何出现了异常。通过linux的ps -eLF|grep pid命令可以查看进程的线程ID(LWP号),但是问题在于如果我们没有在创建线程时记录其线程ID,我们仍然无法得知哪个LWP号是我们想要追踪的。

我们来看一下LWP号是什么,以及如何在创建线程时记录每个线程的LWP号。

pthread_create是基于clone实现的, 创建出来的其实是进程, 但这些进程与父进程共享很多东西, 

共享的东西都不用复制给子进程, 从而节省很多开销, 因此,这些子进程也叫轻量级进程(light-weight process)简称LWP. 每个LWP都会与一个内核线程绑定, 这样它就可以作为独立的调度实体参与cpu竞争. 

LWP被pthread封装后, 以线程面目示人, 它有自己的id, 这里要区分 phtread_create

给LWP分配的id, 和操作系统给LWP分配的进程id. 这两者是不同的, 前者用于标志线程,可以暴露给

用户, 后者其实就是进程的id, 它没有暴露出来, 必须通过系统调用来得到.

 

获取LWP的方法是通过syscall系统调用(具体说明参加man手册),下面是一个例子程序:

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <pthread.h>

//线程处理函数,输出LWP号
void *func(void *argv)
{
    //获取LWP的方法1
    int lwp;
    lwp = syscall(__NR_gettid);
    printf("lwp[%d]\n", lwp);
    
    //获取LWP的方法2
    int lwp2;
    lwp2 = syscall(SYS_gettid);
    printf("lwp2[%d]\n", lwp2);
    sleep(50);
}

int main(void)
{
    pthread_t thd;
    pthread_create(&thd, NULL, func, NULL); //创建线程
    sleep(60);
    return 0;
}

在获取LWP号以后,接下来就是通过strace命令对线程进行追踪了。

strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

 

在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界 里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因。这就是调试程序出现的原因。strace是一个必不可少的 调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面)。

strace的参数有很多,常见的参数介绍如下:

-o filename  将strace的输出写入文件filename 

-p pid      跟踪指定的进程pid. 

-t   在输出中的每一行前加上时间信息. 

-tt  在输出中的每一行前加上时间信息,微秒级.  

-T   显示每一调用所耗的时间. 

-f   跟踪由fork调用所产生的子进程. 

-ff  如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程     号. 

举个例子:我们对tcp_client程序做一个小小的改动,在通过pthread_create创建线程后,每个线程里都通过syscall函数记录其LWP号,同时记录该LWP号对应的数据类型。如果程序再次出现文章开头时提到的异常状况,这时我们可以通过“strace -o tcp_client.txt -tt -p 欲追踪的LWP号”,这样就很快就能知道发生异常的线程在做哪些系统调用了。

总结:在设计程序的时候,一定要考虑将来的维护问题。对于多线程程序,其调试会更加困难,通过在创建线程中记录LWP号和对应的线程功能,可以为以后的调试提供很大帮助。

参考文章:

1、关于Linux的进程和线程

http://kenby.iteye.com/blog/1014039

2、linux strace命令:

http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316692.html

本文出自 “篮彩大神” 博客,请务必保留此出处http://lancaidashen.blog.51cto.com/11086793/1734196

目录
相关文章
|
12月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
1078 1
二、Linux文本处理与文件操作核心命令
|
12月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
775 137
|
12月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
1708 58
|
11月前
|
存储 安全 Linux
Linux卡在emergency mode怎么办?xfs_repair 命令轻松解决
Linux虚拟机遇紧急模式?别慌!多因磁盘挂载失败。本文教你通过日志定位问题,用`xfs_repair`等工具修复文件系统,三步快速恢复。掌握查日志、修磁盘、验重启,轻松应对紧急模式,保障系统稳定运行。
1636 2
|
12月前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
895 16
|
12月前
|
存储 Oracle Java
|
12月前
|
缓存 监控 Linux
Linux内存问题排查命令详解
Linux服务器卡顿?可能是内存问题。掌握free、vmstat、sar三大命令,快速排查内存使用情况。free查看实时内存,vmstat诊断系统整体性能瓶颈,sar实现长期监控,三者结合,高效定位并解决内存问题。
1020 0
Linux内存问题排查命令详解
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2682 10
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
559 83
|
11月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
367 6