localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
localtime() function is invoking ___lll_lock_wait_private() which is making the thread to go deadlock
我见过很多问题,___lll_lock_wait_private ()
陷入僵局。但是它们的调用堆栈是不同的。他们的代码是调用malloc()
或free()
或fork()
。
但就我而言,我有一个 Log 类,它正在尝试打印日志。该日志使我的线程陷入僵局。
请参阅下面的调用堆栈,
#0 0x000000fff4c47b9c in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x000000fff4bf0364 in __tz_convert () from /lib64/libc.so.6
#2 0x000000fff4bee2c0 in localtime () from /lib64/libc.so.6
#3 0x000000fff5167188 in getTimeStr() () from /usr/sbin/sajet/sharedobj/liblibLite.so
#4 0x000000fff516756c in LogClass::logBegin() () from /usr/sbin/sajet/sharedobj/liblibLite.so
#5 0x000000fff5318c90 in DaemonCtrlServer::strtDaemon(daemonInfo&) () from /usr/sbin/sajet/sharedobj/libDaemonCtlServer.so
#6 0x000000fff531abc0 in DaemonCtrlServer::restrtDiedDaemon(daemonInfo&) () from /usr/sbin/sajet/sharedobj/libDaemonCtlServer.so
#7 0x000000fff531ae64 in DaemonCtrlServer::handleChildDeath() () from /usr/sbin/sajet/sharedobj/libDaemonCtlServer.so
#8 0x00000000100080ac in sj_initd::DaemonDeathHandler() ()
#9 0x000000001000b8f8 in sj_initd::SignalHandler(int) ()
#10 0x00000000100080e8 in sj_initd_SigHandler::sj_initdSigHandler(int) ()
#11 <signal handler called>
#12 0x000000fff4bedc00 in __offtime () from /lib64/libc.so.6
#13 0x000000fff4bf02a8 in __tz_convert () from /lib64/libc.so.6
#14 0x000000fff4bee2c0 in localtime () from /lib64/libc.so.6
#15 0x000000fff5167188 in getTimeStr() () from /usr/sbin/sajet/sharedobj/liblibLite.so
#16 0x000000fff516756c in LogClass::logBegin() () from /usr/sbin/sajet/sharedobj/liblibLite.so
#17 0x000000fff52e868c in ConnectionOS::ProcessReadEvent() () from /usr/sbin/sajet/sharedobj/libconnV2.so
#18 0x000000fff52ef354 in ConnectionOSManager::ProcessConns(fd_set*, fd_set*) () from /usr/sbin/sajet/sharedobj/libconnV2.so
#19 0x000000fff52f0a0c in SocketsManager::ProcessFds(bool) () from /usr/sbin/sajet/sharedobj/libconnV2.so
#20 0x000000fff52c51b4 in EventReactorBase::IO (this=0x19a65e80) at EventReactorBase.cpp:361
#21 0x000000fff52c457c in EventReactorBase::React (this=0x19a65e80) at EventReactorBase.cpp:419
#22 0x000000fff52c10cc in Task::Run (this=0x19a65e30) at Task.cpp:222
#23 0x000000fff52c1218 in startTask (t=0x19a65e30) at Task.cpp:152
#24 0x000000001000a9c4 in TaskManager::Start() ()
#25 0x0000000010007538 in main ()
sj_init 是一个守护进程,用于监视系统中其他守护进程的实时状态。当守护程序死亡(这会关闭与sj_init的连接(时,它会尝试重新启动该守护进程。然后,startDaemon()
尝试打印一个日志,该日志正在调用内部调用getTimeStr()
___lll_lock_wait_private
编辑
由于localtime
不是线程安全的,我尝试使用localtime_r
但它也会导致线程陷入死锁。 但根据localtime_r
描述,这是线程安全功能。我在这里做错了什么?
程序在信号处理程序内阻塞,__tz_convert()
从localtime()
调用。信号处理程序中断__tz_convert()
从localtime()
调用。
#0 0x000000fff4c47b9c in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x000000fff4bf0364 in __tz_convert () from /lib64/libc.so.6
#2 0x000000fff4bee2c0 in localtime () from /lib64/libc.so.6
...
#11 <signal handler called>
...
#13 0x000000fff4bf02a8 in __tz_convert () from /lib64/libc.so.6
#14 0x000000fff4bee2c0 in localtime () from /lib64/libc.so.6
...
#25 0x0000000010007538 in main ()
localtime()
似乎不是内在的。
信号处理程序只能调用一组非常具体的函数。向下滚动到此处: https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
localtime()
不在此集合中。
信号处理程序应简短而简单。
您可以设置一个线程进行格式化和日志记录,例如通过管道由信号处理程序提供格式化和记录所需的所有信息。执行此操作的函数列在上面链接的集合中。
#4 0x000000fff516756c in LogClass::logBegin() () from /usr/sbin/sajet/sharedobj/liblibLite.so
#16 0x000000fff516756c in LogClass::logBegin() () from /usr/sbin/sajet/sharedobj/liblibLite.so
注意到LogClass::logBegin
在调用堆栈中出现两次了吗?
你有两个核心问题。
您正在从信号处理程序调用
localtime
。这是不允许的。您正在查看错误的线程堆栈。此线程卡在由其他线程引起的死锁中,然后被中断,再次陷入死锁。它是僵局的受害者(两次!肇事者是另一条线索。
如果要从信号处理程序进行日志记录,则需要非常严格地控制信号处理程序中运行的所有代码,并且需要将"繁重的工作"传递给另一个可以安全调用非重入函数的线程。
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
- Qt:向死/停止线程发送信号
- 多线程Windows GUI应用程序中的死锁
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 一个线程提升的死锁
- 是否访问指针元组和互斥锁线程安全
- C++互斥锁线程优先级
- 解决死锁问题,在主线程中等待多个工作线程完成 (C++11)
- 为什么我的程序在拥有线程的情况下生成LdrpLoaderLock死锁
- 避免单个线程中的死锁
- 这个简单的(原子)锁线程安全吗
- 线程tcp服务器死锁
- 线程安全std::cout的死锁
- 提升线程死锁,任何人都可以检查原因
- 如何在 QT 中使用互斥锁线程开始轮询
- 无锁线程池
- FFMPEG:多线程解码死锁
- 如何在C++Qt程序中调试多线程死锁
- 这种类型的编码是线程安全的还是死锁安全的