2009-11-06 205 views
9

看來,當一個線程是從DllMain在DLL_PROCESS_ATTACH上創建的,它將不會開始,直到所有的dll被加載完畢。由於我需要確保線程在我繼續之前運行,所以我會陷入僵局。有什麼辦法強制線程啓動?在DllMain中創建線程?

回答

10

你不應該做任何的API調用,特別是對於一些像自的DLLMain創建線程或窗口。 Raymond Chen已經寫了很多次了,這裏的one特別相關。

+10

CreateThread是您可以在DllMain中執行的少數幾件事之一,因爲它是對kernel32的調用,保證已經加載。 – 2010-02-06 18:24:53

+2

@Ben Voigt,但要非常小心,因爲如果要求當前的DllMain調用等待新線程返回,很容易死鎖。 – mloskot 2010-11-09 13:43:20

+0

@mloskot:無論你在等待什麼樣的對象,在DllMain中調用等待函數都很糟糕。通常,任何執行DLL代碼的線程都需要在該DLL上引用計數,而不是從代碼下面映射出代碼。這可以防止問題發生,因爲只要線程正在運行,DllMain就不會被調用(用於進程分離)。 – 2010-11-09 14:06:11

5

不可以。您不應該從DllMain調用CreateThread(或任何變量)。嘗試同步會導致死鎖。你究竟想要做什麼?

Best Practices for Creating DLLs

+7

調用CreateThread沒什麼不妥,但是沒有辦法解決這個問題,直到在父線程中完成DllMain處理之後線程纔會被掛起。 – 2010-02-06 18:32:28

0

如果你這樣做,你就會遇到麻煩。你不應該直接或間接地調用你的dll之外的函數(包括C庫調用等)。

如果你不能改變你有的DLL(例如你沒有源代碼),你可能會得到如果你的DLL動態加載後,其他依賴的DLL是初始化。如果你可以避免它,我不會推薦這種方法,因爲找出依賴鏈並不總是微不足道的(例如,如果你的dll導致依賴dll通過COM或其他方式動態加載第三個)。

+2

這裏的第一段是過度泛化。對你知道的DLL進行調用是完全正確的,因爲事實已經在你之前加載了。一般情況下,在大多數情況下,這隻意味着KERNEL32.DLL,這聽起來像是一個嚴重的限制,但你可以用它來引導你擺脫這種情況。 – 2010-04-20 16:08:28

+2

http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx – 2010-04-20 16:33:24

+0

感謝Integer詩人。這正好回答了我來這裏解決的問題。 – 2010-05-05 23:42:23

5

你的線程是做什麼的?

如果您嘗試將內容移動到第二個線程以避免限制您在DllMain中可以執行的操作,那就太難過了。這些並不限制DllMain可以執行的操作,它們限制了DllMain運行時(並保持加載器鎖定)可以執行的操作。如果你的線程需要加載器鎖,它將等待,直到第一個線程完成使用它。如果你的線程不需要加載器鎖,我不明白爲什麼它不能立即繼續下去......但是不存在不需要加載器鎖的線程。 Windows必須在您的線程開始運行之前將DLL_THREAD_ATTACH消息發送給所有DLL,這意味着它也會調用您自己的DllMain,並且Windows可以防止再次入侵。

有沒有辦法解決這個問題。直到DLL_THREAD_ATTACH處理後,線程才能啓動,並且在第一個線程位於DllMain內時不會發生。唯一可行的方法是開始一個新的進程(它有一個獨立的加載程序鎖定,不會阻止等待你的)。

+0

在處理DLL_PROCESS_ATTACH消息期間,我嘗試了一個在'DLLMain()'中使用'CreateThread()'作爲一個非常簡單的工作函數的簡單練習。線程函數使用'Sleep()'1000毫秒。一切正常。我可以看到來自執行'DLL_PROCESS_ATTACH'的初始線程和附加處理期間創建的線程的'DLL_THREAD_ATTACH'消息和'DLL_THREAD_DETACH'消息。然而這個工作線程除了睡眠()之外什麼也沒做。 Kernel32.dll調用應該沒問題。經過VS 2005 Windows 7測試。 – 2016-02-21 18:39:24

+0

奇怪的是,這真的是解決問題的唯一答案。我不知道爲什麼OP決定接受一個不是的答案。 – IInspectable 2016-05-04 20:04:02