本周遇到了好几个core都很有典型性。在这里和大家分享下。

相信有过Linux编程经验的人,肯定都遇到过。感觉周围人很多对core有天然的恐惧感,尤其对刚入行不久的同学来说。当然了,也有工作好几年看到core也束手无策的。今天就分析一下,core,其实大部分都是很容易解决的。如果一个core很难以复现,那么说明还是很复杂的,算是Corner case,可能需要很长时间,脑子里要有很好的运行时状态才可以(阅读源码,学习的是逻辑;将源码对应到运行时的状态,分析一些状态机的转换,再去分析可能会发生的情况)。相信前几篇文章会对这种Corner case的分析与解决打下比较好的基础。

相反,那种每次必现,或者复现比率非常高的case,是非常容易解决的。

多线程必然出core?

如果是你新加入的代码引入的core,实际上非常容易解决的,简单的对比一下修改的diff,然后看一下是否有比较低级的错误。如果发现不了,看是否是多线程的问题?单线程如果没有出core,改成多线程就出core,那么就说明多线程竞争某些变量了:同时修改某些变量导致出问题。这个时候你可能第一反应会加锁。我本人非常反感加锁;即使你加锁的粒度很小,作用域也够小,但是只要是加锁,就代表有阻塞,就代表维护起来会很麻烦。这些共享变量真的那么值得加锁吗?可否换成局部变量?如果他是一块动态内存,为了调用某个接口时不要频繁申请释放内存(比如这个接口每秒几千次的调用),那么初始化时候申请一块内存是绝对合理的:请把它设置为线程变量吧。每个线程初始化时候申请这块内存。

当然了你如果实现的是一个框架或者架构调用的接口,这个接口要做到线程安全的。那么看起来你并不能控制这个线程什么时候启动;线程数目会是多少个,那么就没有办法了吗?

实际上,方法有很多,比如,你可以在一个map中维护一个“线程”变量的对应关系

__gnu_cxx::hash_map< pid_t, void *> thread_data_map;
void * thread_buffer;
std::map<pid_t, void *>::iterator it;
lock
it = thread_data_map.find(pid);
if (it == thread_data_map.end()) {
//init "thread data"
thread_data_map[pid] = create_buffer();
} else {
thread_buffer = it->second;
}
unlock

这里不得不使用了一个锁。实际上由于线程数是有限的,因此这个效率还好。我本周实现了一个qps可以达到2000+的在线应用,基本上锁的代价在整个的call stack中可以忽略不计。

当然了,比较好的框架可能会提供OnThreadInit这种接口,那么在这边申请线程变量吧:

int pthread_setspecific (pthread_key_t key, const void *value);

在实现逻辑的函数获取该变量即可:

void *pthread_getspecific (pthread_key_t key);

什么时候要使用线程变量?看多线程下是否对该变量有写操作,如果有就要申请线程变量(或者加锁),否则必然出core。

不要给自己埋下一个坑:

今天一个同学的core看起来是做了一个“优化”,节省了申请变量的时间。

void init() {
my_struct * some_var;
...
some_var->res = new some_res;
some_var->res->set_value1(some_common_value1);
some_var->res->set_value2(some_common_value2);
} void * thread_func(my_struct * some_var) { some_var->res->set_value3(value_3);
...
}

set_value3就是一个出core的原因。这个也是一个典型的多线程必然出core的case。实际上,res没必要提前申请吧。把它改成一个局部变量,性能几乎没有的损耗。当然了,如果这个资源很大,那么就当成线程变量吧。

那么如何分析core?

实际上,上述的场景出现的core如果仅从core本身,可能一时不好排查问题出在哪里;而且core的位置可能还不一样,不可避免的出现替罪羊;比如调用第三方的模块,实际上是自己的全局变量导致到了第三方的调用栈时出core了。因此一定要排查自己的处理是否正确。

确定调用的接口是否线程安全;如果是你的同事,你得确定他说的是对的。就像今天又另外的一个core,调用者坚称他写的是线程安全的,仿佛不是线程安全的就像是代码写的不好似得;最后排查出他写的代码不是线程安全时,他问你什么是线程安全的。

那么回答一下,如何分析core?

首先了解清楚core出现的应用场景,比如长句子处理会有core;多线程处理会有core;特殊字符会有core;这个QA会给你一个比较清楚的说明。然后通过core的call stack去大概确定大概的源码位置。

源码面前,了无秘密。

你读源码,它展现的是逻辑;但是你脑中,要有个runtime的运行时调用栈,多线程的调度;天马行空。

当然了,还是解决不了,开始从core得到更详细的信息吧!看看调用栈的参数是什么,切换一个线程看看其他的几个线程的frame是什么。

还解决不了?

那么它是Corner case,只要把应用在core后立即启动就行了。记得EMC有个bug的选项是unable to root cause, 形容的很贴切。同时不要忘记自我安慰:码的码多了,肯定有bug,谁能保证服务100%呢?

Linux Debugging(八): core真的那么难以追踪吗?的更多相关文章

  1. Linux Debugging(五): coredump 分析入门

    作为工作几年的老程序猿,肯定会遇到coredump,log severity设置的比较高,导致可用的log无法分析问题所在. 更悲剧的是,这个问题不好复现!所以现在你手头唯一的线索就是这个程序的尸体: ...

  2. 在Linux上利用core dump和GDB调试

    段错误(segfault) "段错误"是程序试图操作不允许访问或试图访问的不允许内存的情况.可能导致段错误的原因主要有: 1.试图解引用空指针(你不允许访问内存地址0) 2.试图解 ...

  3. 在Linux上利用core dump和GDB调试segfault

    时常会遇到段错误(segfault),调试非常费劲,除了单元测试和基本测试外,有些时候是在在线环境下,没有基本开发和测试工具,这就需要调试的技能.以前介绍过使用strace进行系统调试和追踪<l ...

  4. debian(kali Linux) 安装net Core

    debian(kali Linux) 安装net Core curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-previ ...

  5. linux下生成core dump文件方法及设置

    linux下生成core dump文件方法及设置    from:http://www.cppblog.com/kongque/archive/2011/03/07/141262.html core ...

  6. 什么是core dump linux下用core和gdb查询出现"段错误"的地方

    什么是core dump   linux下用core和gdb查询出现"段错误"的地方 http://blog.chinaunix.net/uid-26833883-id-31932 ...

  7. linux下用core和gdb查询出现"段错误"的地方【转】

    转自:http://blog.chinaunix.net/uid-30091091-id-5754288.html 原文地址:linux下用core和gdb查询出现"段错误"的地方 ...

  8. 发布项目到 Linux 上运行 Core 项目

    发布项目到 Linux 上运行 Core 项目 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 ASP.Net Core 给我们带来的最大的亮点就是跨平台,我在我电脑(win ...

  9. Visual Studio 2017 通过SSH 调试Linux 上.NET Core

    Visual Studio 2017 通过SSH 调试Linux 上.NET Core 应用程序. 本文环境 开发环境:Win10 x64 Visual Studio 2017 部署环境:Ubuntu ...

随机推荐

  1. WISCO信息组NOIP模拟赛-部落冲突

    传送门 首先肯定考虑树剖,这里没有要求区间加,所以可以用树状数组维护,不会卡常的 这里是边权,可以转化为点权:让每条边连接的较深的节点的点权等于边权即可,然后计算的时候减去lca #include&l ...

  2. poj 1811 随机素数和大数分解(模板)

    Sample Input 2 5 10 Sample Output Prime 2 模板学习: 判断是否是素数,数据很大,所以用miller,不是的话再用pollard rho分解 miller : ...

  3. hdu 5464(dp)

    题意: 给你n个数,要求选一些数(可以不选),把它们加起来,使得和恰好是p的倍数(0也是p的倍数),求方案数. - - 心好痛,又没想到动规 #include <stdio.h> #inc ...

  4. 例10-7 uva10820(欧拉)

    题意:输入n,要求满足1≤x,y≤n,且x,y互素的个数. 若输入2,则答案3为(1,1),(1,2),(2,1);所以欧拉函数求出所有数的phi值,除了1之外都加上phi值的2倍即可 通过推导: p ...

  5. VB6工程在Win10系统打开提示MSCOMCTL.OCX无法加载

    解决办法: 修改.vbp文件中的 00F8754DA1}#2.1#0; MSCOMCTL.OCX 改为 00F8754DA1}#2.0#0; MSCOMCTL.OCX 中间的2.1 改为 2.0

  6. widows下的进程与服务

    进程: 当程序卡死的时候,我们可以直接通过任务管理器来关闭进程. 服务: 在这个界面,我们可以选择启动或者关闭相关服务,还可以选择服务是否自动启动. 以关闭MySQL自启动服务为例:https://j ...

  7. 《Java技术》第一次作业——Java语言基础

    学习总结 Scanner类实现基本数据输入的方法 Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配.然后可以使用不同的 next 方法将得到的标记转换为不同类型的值. ...

  8. 欢迎大家来到DevLegal的博客

    申明:以下博文欢迎转载,转载请注明出处和作者 若非作者原创,则会标记出处与原作者,其余则为原创. 本人在校大学僧一枚,软件工程专业,希望通过将自己的学习心得与体会写出来,勉励自己学习,同时与大家一起分 ...

  9. c# 判断datatable中是否存在某列

    if (datatable.columns.contains("要找的列名"))

  10. 螺旋打印2D数组

    //一破题付出血的代价 多思考!public static void offer(int [][]a){ ,right=a.length-,low=,high=a[].length-; while(l ...