疑难杂症之malloc死锁__lll_lock_wait_private

3 篇文章 0 订阅

查看glibc源码可知, malloc内部是有锁的。那说明malloc是一个线程安全型函数,但是它不是一个可重入函数。重入的意思是,比如当前线程正在做malloc, 如果此时因为某种原因触发了信号,那么操作系统会保存好现场(正在执行的malloc),转而去执行信号处理函数,如果信号处理函数里面又有malloc的调用,那么此时就发生了malloc重入。当malloc重入时,可能导致线程死锁。

main.c 如下:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
using namespace std;
void signal_handler(int signum);

#define NUM 100000

void* test( void* args )
{    
    while(1)    
    {        
        printf("try to malloc in test, thread id = %u\r\n", pthread_self());        
        void *p = malloc(NUM);       
    }    
    
    return NULL;
}

int main()
{         
    signal(SIGTERM, signal_handler); 

    pthread_t thread1;    
    pthread_create(&thread1, NULL, test, NULL);
    
    for(;;)
    {
        printf("malloc in main function, thread id = %u\r\n", pthread_self());
        void *p = malloc(NUM);
    }

    pthread_join(thread1, NULL);

    return 0;
}   
    
void signal_handler(int signum)
{   
    printf("receive SIGTERM, malloc again, thread id = %u\r\n", pthread_self());
    void *p = malloc(NUM);
}

主线程和子线程都一直在做malloc, 信号处理函数也在调用malloc. 此时运行一个脚本,让其不断触发SIGTERM,那么程序运行一段时间之后可能发生死锁。

编译:

g++ main.c -lpthread

运行:

./a.out

查看线程号:

ps  -ef | grep a.out

root       6378   5558  0 11:21 pts/1    00:00:01 ./a.out

同时启动一个javascript, 让其不断触发SIGTERM,脚本如下:

# $language = "JScript"
# $interface = "1.0"

function main()
{
    shellCmds();
}
  

function shellCmds()
{
	
	   for(;;)
	   {
		   var cmd1 = "kill 6378";
           crt.Screen.Send(cmd1+"\r\n");
           	   
	   }
	
}

运行一段时间之后系统死锁了:

 查看此时的调用栈:

#0  0x00007f2258ed597e in __lll_lock_wait_private () from /lib64/libc.so.6
#1  0x00007f2258e6fc93 in _L_lock_9971 () from /lib64/libc.so.6
#2  0x00007f2258e6e169 in malloc () from /lib64/libc.so.6     //第二次进入malloc
#3  0x0000000000400840 in signal_handler(int) ()
#4  <signal handler called>
#5  0x00007f2258ec541a in mmap64 () from /lib64/libc.so.6
#6  0x00007f2258e6cbc4 in _int_malloc () from /lib64/libc.so.6
#7  0x00007f2258e6e174 in malloc () from /lib64/libc.so.6       //第一次进入malloc
#8  0x000000000040080e in main ()

然而有时候,malloc的调用可能是间接的,比如往文件里面写log也会调用malloc, 以下是一段写文件的调用栈,最终block在malloc

#0  __lll_lock_wait_private (futex=0x74800018) at ./lowlevellock.c:32
#1  0x76120b08 in __GI___libc_malloc (bytes=bytes@entry=4096) at malloc.c:3063
#2  0x7610548c in __GI__IO_file_doallocate (fp=0x74a43428) at filedoalloc.c:101
#3  0x76118adc in __GI__IO_doallocbuf (fp=fp@entry=0x74a43428) at genops.c:365
#4  0x76115b60 in _IO_new_file_seekoff (fp=0x74a43428, offset=0, dir=1, mode=<optimized out>) at fileops.c:960
#5  0x76117360 in _IO_new_file_attach (fp=fp@entry=0x74a43428, fd=fd@entry=218) at fileops.c:379
#6  0x76111ecc in _IO_vdprintf (d=d@entry=218, format=format@entry=0x765aa1d8 "%u", arg=arg@entry=0x74a43520) at iovdprintf.c:46
#7  0x760f1874 in __GI___dprintf (d=d@entry=218, format=format@entry=0x765aa1d8 "%u") at dprintf.c:33

最后总结:

1 malloc是不可重入函数, 如果重入了可能会死锁。所以信号处理函数里面不能调用malloc.

2 malloc的调用有可能是间接地或者说是隐式的。所以信号处理函数应该尽可能简单, 比如只设置一个flag, 然后让其他线程根据这个flag来做其它事情。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
80%的内容为原创!60%的内容为绝无仅有!由Java培训专家张孝祥老师精心打造的Java Web开发之书。张孝 祥老师领悟新事物的能力极强,非常善于自学和思考,编程反应速度快,调试程序、排查错误更是一绝, 为众多程序员所佩服,他的书值得购买。   本书深入地揭示Java Web开发内幕,细致地解释许许多多来自开发第一线的一知半解的问题。阅读本书,可以为您详细地剖析Java Web开发的全过程,使您轻松地解决在使用Java进行Web应用开发遇到的各类疑难杂症。   本书用途之一:许多公司的技术经理在招聘新员工开始做一个项目之前,都将本书发下去,要求员工熟读此书,以免在项目中走弯路和避免许多潜在的隐患,并对员工说:“先把细节搞得明明白白了再做,这样你我心里都踏实,免得项目做完后自己都不敢肯定有多少隐患。”   本书深刻且通俗地揭示Java Web开发内幕,使您由内而外地明白使用Java进行Web应用开发的全过程——从XML基础知识到HTTP详述及相关体验,从用Tomcat配置Web站点到HttpServletResponse和HttpServletRequest的应用,以及JSP,JavaBean等Java Web开发相关方面都讲解得深入浅出、通俗易懂。   本书适合所有Web应用的开发人员、Java程序员在工作和学习中参考阅读,也适合作为相关专业本科生、研究生的学习参考资料,也可作为相关培训机构的培训教材。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一条叫做nemo的鱼

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值