1. 程式人生 > >【面經筆記】深信服電話二面

【面經筆記】深信服電話二面

  • 三層的紅黑樹的根節點刪除後,怎麼調整

CreateThread 和_beginthreadex的區別? 什麼時候應該使用CreateThread 什麼時候應該使用_beginthreadex?

CreateThread函式是windows函式,_beginthreadex是C/C++函式。

標準C/C++執行庫最初不是為多執行緒而設計的,所以在多執行緒環境中會出問題的庫變數和函式有很多,如:errno。

為了保證C/C+多執行緒應用程式的正常執行,必須建立一個資料結構,並使之與使用了C/C++執行庫函式的每個執行緒關聯。然後,在呼叫C/C++執行庫函式時,那些函式必須知道去查詢主調執行緒的資料塊,從而避免影響到其他執行緒

。(我感覺這有點神似 執行緒區域性儲存的概念)

那麼,系統在建立新的執行緒時,如何知道要分配這個資料塊呢?答案是不知道,系統並不知道應用程式是用C/C++寫的,不知道你呼叫的函式並非是天生執行緒安全的。一定不要呼叫作業系統的CreateThread函式,相反,必須呼叫C/C++執行庫函式_beginthreadex。

_beginthreadex函式在創 建執行緒的時候分配了一個tiddata堆結構並和執行緒本身關聯起來。tiddata的作用除了儲存執行緒函式入口地址之外,還有一個重要的作用就是: C執行時庫中有些函式需要通過這個結構來儲存和獲取一些資料,比如說errno之類的執行緒全域性變數。

當一個執行緒呼叫一個要求tiddata結構的執行時庫函式的時候,將發生下面的情況:執行時庫函式試圖獲取執行緒資料塊的地址,如果沒有獲取到,函式就會 現場分配一個 tiddata結構,並且和執行緒相關聯,於是問題出現了,如果不通過_endthreadex函式來終結執行緒的話,這個結構將不會被撤銷,記憶體洩漏就會出現了。(對於一個CreateThread函式建立的執行緒,誰會呼叫_endthreadex呢?)

Dll的入口函式是什麼?

入口函式是DLLMain。

系統是在什麼時候呼叫DllMain函式的呢?靜態連結時,或動態連結時呼叫LoadLibrary和FreeLibrary都會呼叫DllMain函式。這些呼叫是通知性質的,通常被DLL用來執行一些與程序或執行緒有關的初始化和清理工作

DllMain的第一個引數是該DLL例項的控制代碼,這個值表示一個虛擬記憶體地址,DLL的檔案映像就被對映到程序地址空間中的這個位置。

DllMain的第二個引數fdwReason指明瞭系統呼叫Dll的原因,它可能是:
DLL_PROCESS_ATTACH:程序對映
DLL_PROCESS_DETACH:程序解除安裝
DLL_THREAD_ATTACH:執行緒對映
DLL_THREAD_DETACH:執行緒解除安裝

1、DLL_PROCESS_ATTACH

當系統第一次將一個DLL對映到程序地址空間中時,會呼叫DllMain,併為fdwReason傳入DLL_PROCESS_ATTACH。
注意,只有在第一次對映的時候,才會這樣。如之後,另一執行緒再次顯式載入此DLL,則作業系統只是增加該DLL的使用計數,而不會再次使用DLL_PROCESS_ATTACH來呼叫DllMain。

當一個DLL在處理DLL_PROCESS_ATTACH的時候,應該根據包含在DLL中的函式的需要,執行與程序相關的初始化:如開啟資源,分配記憶體等

DllMain的返回值,也是針對DLL_PROCESS_ATTACH訊息的。對於其餘的三種取值,不起作用。
對於隱式載入,如DllMain返回FALSE,則程式會啟動失敗。對於顯式載入,則會使LoadLibrary返回NULL。

  • DLL載入過程:

建立新程序時,系統會分配程序的地址空間並將exe的檔案映像以及所需DLL檔案映像對映到程序的地址空間。然後,系統建立程序的主執行緒,並用這個執行緒呼叫每個DLL 的DLLMain函式,同時傳入DLL_PROCESS_ATTACH。當所有已對映的DLL都完成對該通知的處理後,系統會讓主執行緒開始執行可執行模組的C/C++啟動時的啟動程式碼,然後執行可執行模組的入口函式(_tmain/_tWinMain)。

  • 顯示載入DLL過程:

程序呼叫LoadLibrary的時候,系統會對DLL進行定位,並將該DLL對映到程序的地址空間中。並使用呼叫LoadLibrary的執行緒去呼叫DLLMain函式,傳入DLL_PROCESS_ATTACH。函式返回true,則執行緒繼續正常執行。

2、DLL_PROCESS_DETACH

當系統將一個DLL從程序地址空間中撤銷對映時,則會向DllMain傳入DLL_PROCESS_DETACH。我們應當在此處放置一些清理程式碼

當使用FreeLibrary時,如該執行緒的使用計數為0時,作業系統才會使用DLL_PROCESS_DETACH來呼叫DllMain。如使用計數大於0,則只是單純的減少該DLL的計數。

3、DLL_THREAD_ATTACH

當程序建立一個執行緒,則系統會檢查當前已對映到該程序空間中的所有DLL映像,並用DLL_THREAD_ATTACH來呼叫每個DLL的DllMain。這告訴DLL需要執行與執行緒相關的初始化。且由新建立的執行緒負責執行DLLMain函式。

當系統將一個新的DLL對映到程序的地址空間時,如果已經有多個執行緒在執行,系統也不會讓任何已有的執行緒用DLL_THREAD_ATTACH呼叫DLLMain函式。

只有當所有DLL都完成了對DLL_THREAD_ATTACH的處理後,新執行緒才會執行它的執行緒函式。
另外,主執行緒不可能用DLL_THREAD_ATTACH來呼叫DllMain,因為主執行緒必然是在程序初始化的時候,用DLL_PROCESS_ATTACH呼叫DllMain的。

4、DLL_THREAD_DETACH

執行緒若要終止,會呼叫ExitThread,但是系統不會立即終止執行緒,而是會讓這個即將結束的執行緒用DLL_THREAD_DETACH來呼叫當前程序地址空間中的所有DLL映象的DllMain函式,告訴DLL執行與執行緒相關的清理工作
當每個DLL的DllMain都處理完後,系統才會真正的結束程序。

DLLMain函式在原始碼中不是必需的,連線DLL的時候,如果連結器無法在.obj檔案中找到名為DLLMain的函式,那麼它會連結C/C++執行庫的DLLMain函式

如果不提供自己的DllMain,那麼C/C++執行庫會認為我們不關心DLL_THREAD_ATTACH、DLL_THREAD_DETACH通知。

給你程式碼,如何優化演算法

1)Profile效能分析,找出效能瓶頸,因為80%的時間是在執行20%的程式碼,找出20%的程式碼。
2)針對性地修改語法、演算法、資料結構、甚至框架,以解決瓶頸。

CUDA程式設計的詳細過程,詳細介紹一個演算法在cpu和gpu下分別是怎麼做的,如何優化CUDA

MFC訊息機制 ,各種訊息型別

描述TCP三次握手四次揮手,TCP的半關閉、半開啟、同時關閉

  • 半關閉

TCP提供了連線的一端在結束它的傳送後還能接收來自另一端資料的能力。這就是所謂的半關閉
某一端已經完成資料傳送,因此傳送一個檔案結束(FIN)給另一端,但還想接收另一端傳送來的資料,直到它給我傳送檔案結束(FIN)。

  • 半開啟

如果一方已經關閉或異常終止連線而另一方卻不知道,稱為半開啟。
處於半開啟的連線,如果雙方不進行資料通訊,是發現不了問題的,只有在通訊時才真正的察覺到這個連線已經處於半開啟狀態,如果雙方不傳輸資料的話,仍處於連線狀態的一方就不會檢測另外一方已經出現異常。

它每隔一段時間會超時,超時後會檢查連線是否空閒太久了,如果空閒的時間超過了設定時間,就會發送探測報文。然後通過對端是否響應、響應是否符合預期,來判斷對端是否正常,如果不正常,就主動關閉連線,而不用等待HTTP層的關閉了。
當伺服器傳送探測報文時,客戶端可能處於4種不同的情況:仍然正常執行、已經崩潰、已經崩潰並重啟了、由於中間鏈路問題不可達。在不同的情況下,伺服器會得到不一樣的反饋。

  • 同時關閉

上述為一方先發送第一個FIN執行主動關閉。雙方都執行主動關閉也是可能的。TCP協議允許這樣的同時關閉

如果應用程式同時傳送FIN,則在傳送後會首先進入FIN_WAIT_1狀態。在收到對端的FIN後,回覆一個ACK,會進入CLOSING狀態。在收到對端的ACK後,進入TIME_WAIT狀態。

同時關閉時兩端都會進入TIME_WAIT狀態。

  • 專案的最大難點在哪裡,給你一個新任務,你如何去完成?