簡體   English   中英

退出無法設置錯誤代碼

[英]exit fails to set error code

我有一個C ++ Windows程序無法設置退出代碼。 該程序非常復雜,我目前無法通過簡單的測試用例重現這一點。 我知道該程序調用exit(1)因為我在該行上有一個斷點。 在我跳過它之后,調試器(VS2010)立即打印The program program.exe has exited with code 0 (0x0). 當我從shell運行它時, %ERRORLEVEL%也設置為0。

我使用subsystem:console和plain old main (沒有WinMain)。

這僅發生在Windows Server 2008 R2上,而不是在我的Windows 8.1筆記本電腦上。 我在兩者上運行相同的可執行文件。

我曾嘗試使用exit_exitExitProcessreturn (違規調用在main ),但這些似乎都沒有任何效果。 我也試圖返回其他代碼,也沒有結果。

有一個類似的問題,但我無法重現其中描述的結果。 我的程序確實使用線程。

我該如何處理調試此問題? 我很困惑。

我試圖使用exit,_exit,ExitProcess和return

您已經消除了所有合理的解釋,特別是使用ExitProcess()。 只剩下一種可能性,你需要嘗試TerminateProcess()。 如果仍然沒有設置退出代碼,那么你需要將該機器推出第4層窗口。

但期望它現在有效。 ExitProcess()和TerminateProcess()之間的區別在於前者確保終止通知所有DLL。 用fdwReason = DLL_PROCESS_DETACH調用它們的DllMain()函數。 這讓DLL有機會做一些像調用Exit / TerminateProcess()本身一樣的東西,從而搞砸了退出代碼。

如果您沒有所有源代碼,那么查找這樣的DLL可能會很困難。 也可能是一個注入的,這些天周圍有太多。 最好的辦法是在系統調用上設置一個斷點,這樣你就可以在行為中捕獲它,你可能想要這樣做。

進入main()后,使用Debug> New Breakpoint> Break at Function並輸入{,,ntdll.dll}_NtTerminateProcess@8 按F5,調試器現在在程序終止之前停止。 查看調用堆棧以找到邪惡的行為者。

在多線程程序中涉及exit(),_ exit(),ExitProcess()和其他程序的奇怪症狀 - 特別是如果主機之間的症狀不同 - 有一個變量的氣味被不同的線程修改或訪問,沒有同步。

查看鏈接到的另一個線程,看起來您正在使用volatile變量在線程之間進行通信,但不使用任何形式的同步(例如,訪問該變量值的代碼和修改該值需要合作的代碼通過臨界區,互斥體或類似構造)。

這一點間接證據使氣味變得更強烈。

我懷疑的基本問題是將變量聲明為volatile既不必要也不足以確保變量總是具有對程序有意義的值。 特別是,當修改僅部分完成時,防止修改變量的線程被搶占,並且另一個線程嘗試訪問或修改受影響的變量是不夠的。

如果你查閱Herb Sutter的一些文章(特別是那些關注他的“本周大師”系列中的線程同步的文章),你會發現為什么會這樣的詳細解釋。 其他作者也描述了這些事情,但薩特的文章是我記得的。

解決方案是引入一些同步方法,並為程序中的每個線程在訪問或修改它們之間共享的變量之前虔誠地使用它。 這可以避免各種問題(競爭條件,操作被中途搶占),這些問題會導致您描述的症狀。

通過使用調試器很少發現這些問題。 原因是症狀是一種緊急性質。 在不同的執行線程中,必須同時發生幾種不太可能且通常是獨立的事件。 調試器通常會改變程序中事件的時間,並且時序是出現症狀的關鍵考慮因素。

選項包括使關鍵變量成為原子(因此特定操作不能被搶占),關鍵部分(線程在程序中顯式合作)或互斥(根據定義,允許不同程序中的線程在訪問共享內存之前明確地協作) 。

是的,這會在您的程序中引入一個瓶頸 - 每個線程都必須會合並並可能相互等待。 這可能會影響程序的吞吐量。 有些人主張使用volatile變量來避免這種擔憂。 通常情況下,結果是長期運行程序中的間歇性症狀,如您在此問題中所描述的以及您鏈接到的“類似問題”。

無論您使用標准的同步方法(例如,在C ++ 11中引入)還是使用特定於Windows的方法(WIN API函數),都無關緊要。 重要的是你使用有意的同步方法,而不是僅僅使變量變為volatile。 不同的同步選項有不同的權衡,因此您需要做出與您的程序需求相關的決策。

另一個考慮因素是發出所有線程的信號,以便它們干凈地關閉,等到它們全部關閉,捕獲它們的退出代碼,然后退出程序。 在運行main()的線程中執行此操作通常不太容易出錯 - 這最終會啟動進程,因此更有可能訪問正確清理所需的信息。 如果另一個線程決定程序需要退出,那么如果它需要回到main()來執行它,那就更好了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM