疑难杂症之malloc死锁__lll_lock_wait_private

2023-10-12 22:40

本文主要是介绍疑难杂症之malloc死锁__lll_lock_wait_private,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

查看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 100000void* 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来做其它事情。

这篇关于疑难杂症之malloc死锁__lll_lock_wait_private的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/198947

相关文章

linux 下Time_wait过多问题解决

转自:http://blog.csdn.net/jaylong35/article/details/6605077 问题起因: 自己开发了一个服务器和客户端,通过短连接的方式来进行通讯,由于过于频繁的创建连接,导致系统连接数量被占用,不能及时释放。看了一下18888,当时吓到了。 现象: 1、外部机器不能正常连接SSH 2、内向外不能够正常的ping通过,域名也不能正常解析。

一次生产环境大量CLOSE_WAIT导致服务无法访问的定位过程

1.症状 生产环境的一个服务突然无法访问,服务的交互过程如下所示: 所有的请求都是通过网关进入,之后分发到后端服务。 现在的情况是用户服务无法访问商旅服务,网关有大量java.net.SocketTimeoutException: Read timed out报错日志,商旅服务也不断有日志打印,大多是回调和定时任务日志,所以故障点在网关和商旅服务,大概率是商旅服务无法访问导致网关超时。 后

【Linux修行路】线程安全和死锁

目录 ⛳️推荐 一、线程安全 1.1 常见的线程不安全情况 1.2 常见的线程安全情况 1.3 常见的不可重入情况 1.4 常见可重入的情况 1.5 可重入与线程安全的联系 1.6 可重入与线程安全的区别 二、死锁 2.1 死锁的四个必要条件 2.2 如何避免产生死锁? ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大

selenium的webdriver三种等待方式(显式等待WebDriverWait+implicitly_wait隐式等待+sleep强制等待)

隐式等待是等页面加载,不是等元素!!! 1、显式等待  一个显式等待是你定义的一段代码,用于等待某个条件发生然后再继续执行后续代码。显式等待是等元素加载!!! from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import

c++ public、protected 、 private访问修饰符详解

在 C++ 中,访问修饰符用于控制类的成员(数据成员和成员函数)的访问权限。主要的访问修饰符有三个:public、protected 和 private。每种修饰符的访问规则如下: 1. public 定义:public 修饰符表示该成员对所有代码都是可见的,任何对象都可以访问和修改。作用:允许类外部的代码访问这些成员。 class Example {public:int publicVa

访问修饰符public、protected、private,基于C++

一、基本概念 公有(public)成员   公有成员在程序中类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值, 私有(private)成员  私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。 默认情况下,类的所有成员都是私有的。例如在下面的类中,width 是一个私有成员,这意味着,如果您没有使用任何访问修饰符,类的成

模拟线程死锁——Thread学习笔记

记录一下之前写过的一段模拟死锁的代码: /*** 模拟死锁** @author lixiang* @date 2018年10月12日 - 9:51* @history 2018年10月12日 - 9:51 lixiang create.*/public class HoldLockDemo {private static Object[] lock = new Object[10];priv

QGraphicsView、QGraphicsScene和QGraphicsItem图形视图框架(二)疑难杂症

疑难杂症1 1.问题: 设置场景的背景图片时,采用setBackgroundBrush()方法和重写drawBackground()函数得到的结果很不一样,而且通过setSceneRect设置场景原点位置之后得到的结果也有很大区别。 如下图 第一个和第三个中重写了QGraphicsScene的drawBackground()函数,区别在于第一个的场景原点在左上角,第三个的原点在中心。

【硬刚Java并发】JUC基础(六):Lock 同步锁

本文是对《【硬刚大数据之学习路线篇】从零到大数据专家的学习指南(全面升级版)》的Java并发部分补充。 显示锁 Lock 在 Java 5.0 之前,协调共享对象的访问时可以使用的机制只有 synchronized 和 volatile 。Java 5.0 后增加了一些新的机制,但并不是一种替代内置锁的方法,而是当内置锁不适用时,作为一种可选择的高级功能。 ReentrantLock 实

解决 The sandbox is not sync with the Podfile.lock问题

问题描述: github / sourcetree下载的Demo,很多时候使用到CocoaPods,有的时候因为依赖关系或者版本问题不能编译运行。出现例如The sandbox is not sync with the Podfile.lock问题时候,如下所示 diff: /../Podfile.lock: No such file or directory diff: Manifest.l