在使用zeromq 退出的時候還遇到一點坑,對于服務deaman(守護行程)化的行程可能會遇到這個問題,
現象:
這個問題導致的現象是服務一旦關閉(stop),就會 core dump,core dump 的資訊如下,意思大概是使用了無效的描述符,

(gdb) bt
#0 0x00007f522e2le387 in raise () from /lib64/libec.so.6
#1 0x00007f522e21fbb8 in abort () from /lib64/libec.so.6
#2 0x00000000004d5909 in zmq::zmq_abort (errmsg_errmsg_@entry=0x7f522e37025f "Bad file descriptor") at src/err.cpp :88
#3 0x00000000004d5242 in zmq::epoll_t::add_fd_(this=0x1b25520, fd_efd_@entry=15, events_events_@entry=0x1b28580) at src/epoll.cpp:100
#4 0x00000000004e42e2 in zmq::socket_base_t::start_reapiing (this=0x1b28140, poller_=<optimized out>) at src/socket_base.cpp:1465
#5 0x000000000004ela63 in zmq::reaper_t::process_reap (this=0xlb21580, socket_=<optimized out>) at src/reapercpp:133
#6 0x000000000004ele7c in zmq::reaper_t::in_event (this=0x21b21580) at src/reaper.cpp:104
#7 0x00000000004d508e in zmq::epoll_t::loop (this=0x1b255520) at src/epoll.cpp:206
#8 0x00000000004f0d45 in thread_routine (arg_=0x1b255778) at src/thread.cpp:257
#9 0x00007f522f23dea5 in start_thread () from /lib64/libpthread.so.0
#10 0x00007f522e2e6b0d in clone () from /lib64/libc.so.6
產生的原因:
我們服務的 Server 是個 static Instance 單例,在 Server 里默認分配記憶體的方式宣告了 zeromq 的 Context 和 socket,Server 單例創建的時候,就會創建好 Context 和 socket,
class Server
{
....
private:
zmq::context_t m_context;
zmq::socket_t m_socket;
}
在啟動服務后,會判斷是否需要守護化(daemon化),如果需要,就會 fork 行程并創建守護行程,主行程退出,
正是主行程退出時沒有呼叫 Context 的銷毀函式,導致子行程退出時,雖然處理了 Context 的銷毀,但是主行程創建的 Context 卻沒有呼叫銷毀函式,導致和 zeromq 內部執行緒還在訪問失效的描述符,從而出現了 core dump,這里需要解釋一下,在 fork 時,子行程也會拷貝父行程的 static 資料,
下面是關于 fork 后父行程和子行程 static 記憶體資料的介紹:
在 fork 函式呼叫時,父行程的記憶體會被復制到子行程中,包括 static 資料的記憶體,這意味著子行程也會擁有與父行程相同的 static 資料,但是它們是相互獨立的,如果在父行程或子行程中修改了 static 資料,則不會影響另一個行程中的 static 資料,
補充一段static類析構呼叫時機的介紹:
對于在 C++ 中宣告為靜態變數的類物件,其解構式會在程式結束時被呼叫,具體來說,靜態物件的解構式會在程式退出 main 函式后,動態庫被卸載之前,以及行程終止時被呼叫,
靜態物件的析構順序和構造順序相反,也就是說,先構造的靜態物件后被析構,后構造的靜態物件先被析構,這一點需要注意,因為不同的靜態物件之間可能存在相互依賴的關系,因此析構順序可能會對程式的正確性產生影響,
需要注意的是,如果靜態物件是在元件中定義的,則其解構式會在元件被卸載之前被呼叫,因此,如果靜態物件依賴于元件中的其他物件或者庫資源,需要注意析構順序的問題,避免出現資源泄漏或者懸掛指標等問題,
另外,對于靜態物件的建構式和解構式,需要確保它們不會產生任何例外,否則可能會導致靜態物件無法正確地被構造或析構,從而產生未定義行為,
解決方法:
將 m_context 和 m_socket 宣告為指標型別,在守護化后的 Init 呼叫中進行初始化,
private:
zmq::context_t * m_context;
zmq::socket_t * m_socket;
這也給我們一些啟示,對于類成員是第三方類,最好宣告為指標,在初始化函式里呼叫初始化,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/547596.html
標籤:C++
上一篇:讀Java性能權威指南(第2版)筆記23_ 性能分析工具
下一篇:蒲公英(分塊)
