Linux 多執行緒程式呼叫malloc,backtrace引發死鎖問題的除錯
最近,參與公司開發一專案,為提高Server端的執行效率,將Server程式設計為多執行緒結構。在一次測試中發現了Server無任何響應的問題,我的第一判斷是Server程式出現了死鎖。於是,使用pstack命令檢視各執行緒的堆疊狀態。
# pstack 程序號
Thread 9 (Thread 0x7fe82b43a700 (LWP 29656)):
#0 0x00007fe82f3681bd in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007fe82f363d1d in _L_lock_840 () from /lib64/libpthread.so.0
#2 0x00007fe82f363c3a in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x00007fe8301f671d in _dl_fini () from /lib64/ld-linux-x86-64.so.2
#4 0x00007fe82d6e1a49 in __run_exit_handlers () from /lib64/libc.so.6
#5 0x00007fe82d6e1a95 in exit () from /lib64/libc.so.6
#6 0x00000000004048c3 in printRecvSignalNum (sign=<optimized out>) at AC.c:257
#7 <signal handler called>
#8 0x00007fe82f3681bb in __lll_lock_wait () from /lib64/libpthread.so.0
#9 0x00007fe82f363d02 in _L_lock_791 () from /lib64/libpthread.so.0
#10 0x00007fe82f363c08 in pthread_mutex_lock () from /lib64/libpthread.so.0
#11 0x000000000041f802 in cronometer (arg=<optimized out>) at timerlib.c:266
#12 0x00007fe82f361dc5 in start_thread () from /lib64/libpthread.so.0
#13 0x00007fe82d7a073d in clone () from /lib64/libc.so.6
Thread 8 (Thread 0x7fe82ac39700 (LWP 29671)):
#0 0x00007fe82d7ae0fc in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x00007fe82d72bf93 in _L_lock_14932 () from /lib64/libc.so.6
#2 0x00007fe82d729013 in malloc () from /lib64/libc.so.6
#3 0x00007fe8301f4078 in _dl_map_object_deps () from /lib64/ld-linux-x86-64.so.2
#4 0x00007fe8301fa6db in dl_open_worker () from /lib64/ld-linux-x86-64.so.2
#5 0x00007fe8301f5ff4 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#6 0x00007fe8301f9feb in _dl_open () from /lib64/ld-linux-x86-64.so.2
#7 0x00007fe82d7dafc2 in do_dlopen () from /lib64/libc.so.6
#8 0x00007fe8301f5ff4 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#9 0x00007fe82d7db082 in __libc_dlopen_mode () from /lib64/libc.so.6
#10 0x00007fe82d7b4565 in init () from /lib64/libc.so.6
#11 0x00007fe82f366bb0 in pthread_once () from /lib64/libpthread.so.0
#12 0x00007fe82d7b467c in backtrace () from /lib64/libc.so.6
#13 0x00007fe82eb4ead9 in procAssertStackInfo () at cc_common.c:545
#14 0x00007fe82eb4f240 in procAssertEntry (file=0x0, func=0x0, line=0, exp_str=0x0, sign=11) at cc_common.c:597
#15 <signal handler called>
#16 0x00007fe82d72477d in malloc_consolidate () from /lib64/libc.so.6
#17 0x00007fe82d726385 in _int_malloc () from /lib64/libc.so.6
#18 0x00007fe82d729a14 in calloc () from /lib64/libc.so.6
#19 0x0000000000432287 in UpdateStasInfoIntoMySQL ( [email protected]=0x7fe82ac38b68, [email protected]=0x7fe82ac37f90, [email protected]=0x7fe81c01af10) at ACDisplay.c:3256
#20 0x0000000000432bc4 in UpdateStationListMySQL (listStas=0x7fe82ac38b68, [email protected]=0x0, pWtpHashNode=0x7fe81c01af10, [email protected]=0x7fe82ac38ab8) at ACDisplay.c:3585
#21 0x0000000000434607 in UpdateStationList (listStas=0x0, [email protected]=0x7fe82ac38b68, pWtpHashNode=0x7fe82ac38ab8, [email protected]=0x7fe81c01af10) at ACDisplay.c:4716
#22 0x000000000040c4c3 in ACEnterRun ([email protected]=0x7fe81c01af10, [email protected]=0x7fe82ac38d70, dataFlag=CW_FALSE) at ACRunState.c:499
#23 0x00000000004061c9 in CWManageWTP ([email protected] =0x7fe82ac38da8) at ACMainLoop.c:428
#24 0x00000000004069c1 in CWHandleIncomingCapwapPkg (parg=0xe7ab60) at ACMainLoop.c:497
#25 0x000000000040e27f in CWConsumerThread (arg=<optimized out>) at Scheduler.c:234
#26 0x00007fe82f361dc5 in start_thread () from /lib64/libpthread.so.0
#27 0x00007fe82d7a073d in clone () from /lib64/libc.so.6
Thread 7 (Thread 0x7fe82a438700 (LWP 29672)):
#0 0x00007fe82f3681bd in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007fe82f363d02 in _L_lock_791 () from /lib64/libpthread.so.0
#2 0x00007fe82f363c08 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x000000000041a5d5 in CWThreadMutexLock ([email protected]=0xc5f228 <g_wtp_data_hash+5594600>) at CWThread.c:157
#4 0x000000000040697e in CWHandleIncomingCapwapPkg (parg=0xe7d500) at ACMainLoop.c:483
#5 0x000000000040e27f in CWConsumerThread (arg=<optimized out>) at Scheduler.c:234
#6 0x00007fe82f361dc5 in start_thread () from /lib64/libpthread.so.0
#7 0x00007fe82d7a073d in clone () from /lib64/libc.so.6
Thread 6 (Thread 0x7fe829c37700 (LWP 29673)):
#0 0x00007fe82d7ae0fc in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x00007fe82d72b991 in _L_lock_4780 () from /lib64/libc.so.6
#2 0x00007fe82d7251f8 in _int_free () from /lib64/libc.so.6
#3 0x000000000041fc65 in timer_rem (id=8522, free_arg=0x41a367 <CWTimerFreeArgSingleThread>) at timerlib.c:524
#4 0x000000000041adf8 in CWTimerCancelSingleThread (idPtr=<optimized out>) at CWThread.c:909
#5 0x000000000040be4f in CWStopNeighborDeadTimer (pWtpManData=<optimized out>) at ACRunState.c:1920
#6 0x000000000040be91 in CWRestartNeighborDeadTimer (pWtpManData=0x7fe814065720) at ACRunState.c:1935
#7 0x000000000040c08e in ACEnterRun ([email protected]=0x7fe814064be0, [email protected]=0x7fe829c36d70, dataFlag=CW_FALSE) at ACRunState.c:259
#8 0x00000000004061c9 in CWManageWTP ([email protected]=0x7fe829c36da8) at ACMainLoop.c:428
#9 0x00000000004069c1 in CWHandleIncomingCapwapPkg (parg=0xe7d460) at ACMainLoop.c:497
#10 0x000000000040e27f in CWConsumerThread (arg=<optimized out>) at Scheduler.c:234
#11 0x00007fe82f361dc5 in start_thread () from /lib64/libpthread.so.0
#12 0x00007fe82d7a073d in clone () from /lib64/libc.so.6
Thread 5 (Thread 0x7fe829436700 (LWP 29674)):
#0 0x00007fe82f3681bd in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007fe82f363d02 in _L_lock_791 () from /lib64/libpthread.so.0
#2 0x00007fe82f363c08 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x000000000041a5d5 in CWThreadMutexLock ([email protected]=0xc5f228 <g_wtp_data_hash+5594600>) at CWThread.c:157
#4 0x000000000040697e in CWHandleIncomingCapwapPkg (parg=0xe7d2a0) at ACMainLoop.c:483
#5 0x000000000040e27f in CWConsumerThread (arg=<optimized out>) at Scheduler.c:234
#6 0x00007fe82f361dc5 in start_thread () from /lib64/libpthread.so.0
#7 0x00007fe82d7a073d in clone () from /lib64/libc.so.6
從pstack結果可以看出,執行緒9到執行緒5已經死鎖。接下來,詳細分析各執行緒的狀態。經分析發現真正引起死鎖的源頭是執行緒8。
執行緒8:
執行過程有一步呼叫了calloc 函式,向linux系統申請堆疊空間。
#18 0x00007fe82d729a14 in calloc () from /lib64/libc.so.6
在malloc尚未完成的時候,該執行緒接收到了sign 11
#14 0x00007fe82eb4f240 in procAssertEntry (file=0x0, func=0x0, line=0, exp_str=0x0, sign=11) at cc_common.c:597
在我們專案中,已將訊號11過載,並在訊號處理函式中呼叫了backtrace函式,而backtrace在執行中會呼叫malloc函式
#2 0x00007fe82d729013 in malloc () from /lib64/libc.so.6
因此,我們知道了死鎖原因,當malloc正在執行時,被訊號11打斷而去執行了backtrace函式,backtrace函式中又呼叫了malloc函式,此種情況,堆疊鎖被連續lock了兩次,因而執行緒8被阻塞,並且,在此之後任何執行緒都無法獲取堆疊鎖,會導致其它執行緒阻塞在諸如malloc或free的操作上。現在,我們檢視下是否有執行緒阻塞在諸如malloc或free的操作上?
Thread 6 (Thread 0x7fe829c37700 (LWP 29673)):
#0 0x00007fe82d7ae0fc in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x00007fe82d72b991 in _L_lock_4780 () from /lib64/libc.so.6
#2 0x00007fe82d7251f8 in _int_free () from /lib64/libc.so.6
可見,執行緒6被阻塞在free操作上;再次分析我們的程式碼,執行緒6已經佔用了一個鎖(公司專案中定義的),且再無機會釋放。再看其它執行緒,執行緒5,7,9都在等待鎖,且永遠等待不到。
那麼,如何解決這個問題的呢?
由以上分析,訊號11是引發死鎖的導火線,訊號11一般是由記憶體越界引起,排查最近開發的程式碼解決掉這個錯誤,但Sever死鎖的風險仍然存在。因此,若想從根本上解決死鎖的風險,則backtrace不可以作為訊號處理函式使用。
總結:訊號處理函式必須是可重入函式。以下是可重入函式和不可重入函式的定義。
可重入函式:重入意味著這個函式可以重複進入,可以被並行呼叫,可以被中斷,它只使用自身棧上的資料變數,它不依賴於任務環境,在多工排程過程中,它是安全的,不必擔心資料出錯。
不可重入函式:不可重入,意味著不可被並行排程,否則會產生不可預料的結果,這些函式內一般使用了靜態(static)的資料結構,使用了malloc()或者free()函式,使用了標準I/O函式等等。
相關推薦
Linux 多執行緒程式呼叫malloc,backtrace引發死鎖問題的除錯
最近,參與公司開發一專案,為提高Server端的執行效率,將Server程式設計為多執行緒結構。在一次測試中發現了Server無任何響應的問題,我的第一判斷是Server程式出現了死鎖。於是,使用pstack命令檢視各執行緒的堆疊狀態。 # pstack 程
使用C++編寫linux多執行緒程式
前言 在這個多核時代,如何充分利用每個 CPU 核心是一個繞不開的話題,從需要為成千上萬的使用者同時提供服務的服務端應用程式,到需要同時開啟十幾個頁面,每個頁面都有幾十上百個連結的 web 瀏覽器應用程式,從保持著幾 t 甚或幾 p 的資料的資料庫系統,到手機上的一個有良好使用者響應能力的 app,為了充分
[C++11 std::thread] 使用C++11 編寫 Linux 多執行緒程式
前言 在這個多核時代,如何充分利用每個 CPU 核心是一個繞不開的話題,從需要為成千上萬的使用者同時提供服務的服務端應用程式,到需要同時開啟十幾個頁面,每個頁面都有幾十上百個連結的 web 瀏覽器應用程式,從保持著幾 t 甚或幾 p 的資料的資料庫系統,到手機上的一個有良好使用者響應能力的 app,為了
Linux多執行緒消費者和生產者模型例項(互斥鎖和條件變數使用)
條件變數簡單介紹: 條件變數是執行緒可以使用的另一種同步機制。條件變數與互斥量一起使用的時候,允許執行緒以無競爭的方式等待特定的條件發生。條件本身是由互斥量保護的。執行緒在改變條件變數狀態前必須先鎖住互斥量。另一種是動態分配的條件變數,則用pthread_cond_ini
linux下C開發多執行緒程式
轉:https://blog.csdn.net/lingfemg721/article/details/6574804 linux下用C開發多執行緒程式,Linux系統下的多執行緒遵循POSIX執行緒介面,稱為pthread。 #
作業系統,核心定時器:使用“訊號”建立一種使用者空間機制來測量一個多執行緒程式的執行時間。
核心是一個作業系統的核心。它負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效能和穩定性。 定時器是Linux提供的一種定時服務的機制,它在某個特定的時間喚醒某個程序來進行工作。核心在時鐘中斷髮生後檢測各定時器是否到期,在li
linux多執行緒程式設計,用 pthread_cond_timedwait 代替sleep
摘要:多執行緒程式設計中,執行緒A迴圈計算,然後sleep一會接著計算(目的是減少CPU利用率);存在的問題是,如果要關閉程式,通常選擇join執行緒A等待執行緒A退出,可是我們必須等到sleep函式返回,該執行緒A才能正常退出,這無疑減慢了程式退出的速度。當然,你可以terminate執行緒A,但
對於多執行緒程式,單核cpu與多核cpu是怎麼工作的
此文中的大部分資料來自於網路上,我只是覺得把有道理的整理一下,方便以後查閱。 1.多執行緒在單核和多核CPU上的執行效率問題的討論a1: 多執行緒在單cpu中其實也是順序執行的,不過系統可以幫你切換那個執行而已,其實並沒有快(反而慢)多個cpu的話就可以在兩個cpu中同時執行了.....
vector在多執行緒下的問題,迭代器失效造成程式崩潰。
最近在做專案的過程中,遇到STL中vector的多執行緒訪問問題。問題大概是這樣的:有一個全域性的vector,一個寫程序對該vector進行插入操作(push_back()),同時有一個讀程序在監視該vector的內容並對其進行顯示(操作:size(), at(i)),沒有
linux多執行緒程式設計,你還在用sleep麼?用pthread_cond_timedwait吧
摘要:多執行緒程式設計中,執行緒A迴圈計算,然後sleep一會接著計算(目的是減少CPU利用率);存在的問題是,如果要關閉程式,通常選擇join執行緒A等待執行緒A退出,可是我們必須等到sleep函式返回,該執行緒A才能正常退出,這無疑減慢了程式退出的速度。當然,你可以terminate執行緒A,但這樣做
為什麼linux下多執行緒程式如此消耗虛擬記憶體
最近遊戲已上線運營,進行伺服器記憶體優化,發現一個非常奇妙的問題,我們的認證伺服器(AuthServer)負責跟第三方渠道SDK打交道(登陸和充值),由於採用了curl阻塞的方式,所以這裡開了128個執行緒,奇怪的是每次剛啟動的時候佔用的虛擬記憶體在2.3G,然後每次處理訊息就增加64M,
linux之使用ptrace 跟蹤多執行緒程式
1.ptrace 原型說明 #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); 在使用PTRAC
linux多執行緒程式設計,替代sleep的幾種方式
我只想要程序的某個執行緒休眠一段時間的,可是用sleep()是將整個程序都休眠的,這個可能就達不到,我們想要的效果了。 目前我知道有三種方式: 1 usleep 這個是輕量級的, 聽說能可一實現執行緒休眠, 我個人並不喜歡這種方式,所以我沒有驗證它的可行信(個人不推薦
Linux多執行緒程式設計---執行緒間同步(互斥鎖、條件變數、訊號量和讀寫鎖)
本篇博文轉自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數、訊號量和讀寫鎖。 下面是思維導
LINUX 多執行緒 JNI 回撥 java static
1.Linux 開啟執行緒 //渲染執行緒Rendering void* thread_rendering_process(void *lParam) { unsigned int local_wr; int index; &
linux 多執行緒之訊號量 sem_init
1. 什麼是訊號量 linux sem 訊號量是一種特殊的變數,訪問具有原子性, 用於解決程序或執行緒間共享資源引發的同步問題。 使用者態程序對 sem 訊號量可以有以下兩種操作: 等待訊號量 當訊號量值為 0 時,程式等待;當訊號量值大於 0 時,訊號量減 1,程式
Linux多執行緒學習總結
原文:https://www.cnblogs.com/luoxn28/p/6087649.html Linux多執行緒學習總結 執行緒是程式中完成一個獨立任務的完整執行序列,即一個可排程的實體;程序相當於執行中程式的一種抽象。根據執行環境的排程者的身份,執行緒可分為核心執行緒和使用者執行
Linux多執行緒/多客戶程式設計參考/程式碼
Linux多執行緒/多客戶程式設計參考/程式碼 (1)linux多執行緒程式設計例項及講解 https://blog.csdn.net/m0_37051593/article/details/80719469 (2)Linux多執行緒程式設計——多執行緒與執行緒同步 https://
多執行緒縣互動例項,生產消費
生產者消費者問題是一個非常典型性的執行緒互動的問題。 1. 使用棧來存放資料 1.1 把棧改造為支援執行緒安全 1.2 把棧的邊界操作進行處理,當棧裡的資料是0的時候,訪問pull的執行緒就會等待。 當棧裡的資料時200的時候,訪問push的執行緒就會等待 2. 提供一個生產者(Producer)執
多執行緒--生產者消費者範例,使用lock和condition
上一篇的部落格已經介紹了生產者和消費者,最後還是遺留了一個問題,就是必須Notifyall才能保證喚醒對方執行緒,這樣降低了效率,那麼,有沒有什麼辦法可以指定我們來喚醒哪一個執行緒呢? &