摘要:在使用多线程程序时,有时会遇到程序功能异常的情况,而这种异常情况并不是每次都发生,很难模拟出来。这时就需要运用在程序运行时跟踪线程的手段,而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

linux跟踪线程的方法:LWP和strace命令的更多相关文章

  1. inux跟踪线程的方法:LWP和strace命令

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

  2. 使用 Linux 的 strace 命令跟踪/调试程序的常用选项

    原文:http://linoxide.com/linux-command/linux-strace-command-examples/作者: Raghu 在调试的时候,strace能帮助你追踪到一个程 ...

  3. Linux posix线程库总结

    由于历史原因,2.5.x以前的linux对pthreads没有提供内核级的支持,所以在linux上的pthreads实现只能采用n:1的方式,也称为库实现. 线程的实现,经历了如下发展阶段: Linu ...

  4. Linux编程---线程

    首先说一下线程的概念.事实上就是运行在进程的上下文环境中的一个运行流.普通进程仅仅有一条运行流,可是线程提供了多种运行的路径并行的局面. 同一时候,线程还分为核心级线程和用户级线程.主要差别在属于核内 ...

  5. Linux查看线程

    我的程序在其内部创建并执行了多个线程,我怎样才能在该程序创建线程后监控其中单个线程?我想要看到带有它们名称的单个线程详细情况(如,CPU/内存使用率). 线程是现代操作系统上进行并行执行的一个流行的编 ...

  6. 嵌入式linux应用程序调试方法

    嵌入式linux应用程序调试方法 四 内存工具 五 C/C++代码覆盖.性能profiling工具 四 内存工具 您肯定不想陷入类似在几千次调用之后发生分配溢出这样的情形. 许多小组花了许许多多时间来 ...

  7. Linux中线程使用详解

    线程与进程为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题. 使用多线程的理由之一是和进程相比,它是一种非常"节俭&qu ...

  8. Linux内核线程之深入浅出【转】

    转自:http://blog.csdn.net/yiyeguzhou100/article/details/53126626 [-] 线程和进程的差别 线程的分类 1     内核线程 2     轻 ...

  9. linux系统——线程

    linux系统线程 1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的Unix也支持线程的概念,但是在一个 ...

随机推荐

  1. reboot---重启Linux系统

    reboot命令用来重新启动正在运行的Linux操作系统. 语法 reboot(选项) 选项 -d:重新开机时不把数据写入记录文件/var/tmp/wtmp.本参数具有“-n”参数效果: -f:强制重 ...

  2. C# 将引用的DLL文件放到指定的目录下

    原文:C# 将引用的DLL文件放到指定的目录下 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sweety820/article/details/2 ...

  3. [Angular & Unit Testing] Testing a RouterOutlet component

    The way to test router componet needs a little bit setup, first we need to create a "router-stu ...

  4. jQuery Easy UI Panel(面板)组件

    panel(面板)组件,跟前面的组件使用方法差点儿都差点儿相同,也是从设置一些面板属性.操作面板触发的事件.我们可针对面板对象的操作方法这三个点去学习. 后面有一些组件要依赖于这个组件. 另一点跟前面 ...

  5. Linux 获取上个月的第一秒和上个月的最后一秒

    因为写脚本需求须要获得上个月的第一秒和上个月的最后一秒,查阅了相关资料,并通过自己实践.找到了以下这样的方法能满足要求.在此备注,若有其它好的方法.请留言.本人将不胜感激. 获取上个月的第一秒: da ...

  6. 深入理解javascript之原型

    理解原型 原型是一个对象.其它对象能够通过它实现属性继承. 不论什么一个对象都能够成为继承,全部对象在默认的情况下都有一个原型.由于原型本身也是对象,所以每一个原型自身又有一个原型. 不论什么一个对象 ...

  7. [LuoguP4892]GodFly的寻宝之旅 状压DP

    链接 基础状压DP,预处理出sum,按照题意模拟即可 复杂度 \(O(n^22^n)\) #include<bits/stdc++.h> #define REP(i,a,b) for(in ...

  8. Logstash之Logstash inputs(file和redis插件)、Logstash outputs(elasticsearch 和redis插件)和Filter plugins

     前期博客 Logstash安装和设置(图文详解)(多节点的ELK集群安装在一个节点就好) Filebeat啊,根据input来监控数据,根据output来使用数据!!! 请移步, Filebeat之 ...

  9. element-UI实现el-table-column百分比自定义分配

    1.把el-table-column的属性width换位min-width就支持百分比显示了.

  10. 读书笔记-Java设计模式

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! Java的封装性很好,拿访问控制符来讲,没有权限的类或方法是不能访问的.如public,都可访问:p ...