2009-11-06 23 views
9

Dường như khi một luồng được tạo từ bên trong DllMain khi DLL_PROCESS_ATTACH nó sẽ không bắt đầu cho đến khi tất cả các dll đã được tải. Vì tôi cần đảm bảo luồng chạy trước khi tôi tiếp tục, tôi bị bế tắc. Có cách nào để buộc các chủ đề để bắt đầu?Tạo chuỗi trong DllMain?

Trả lời

10

Bạn không nên làm bất kỳ cuộc gọi API, đặc biệt là cho những thứ như tạo chủ đề hoặc cửa sổ, từ DllMain. Raymond Chen đã viết về điều này nhiều lần; đây là one có liên quan đặc biệt.

+10

CreateThread là một trong số ít những thứ bạn có thể làm bên trong DllMain, bởi vì đó là một cuộc gọi đến kernel32 được đảm bảo đã được nạp. –

+2

@Ben Voigt nhưng cực kỳ cẩn thận, vì thật dễ dàng để có được khóa chết nếu cuộc gọi DllMain hiện tại được yêu cầu chờ trả lại từ chuỗi mới. – mloskot

+0

@mloskot: Gọi các chức năng chờ trong 'DllMain' rất tệ dù bạn đang chờ loại đối tượng nào. Nói chung, bất kỳ chuỗi nào đang thực thi mã từ một DLL cần phải có số tham chiếu trên DLL đó, ít mã được ánh xạ từ bên dưới nó. Điều này ngăn cản sự cố xảy ra, vì 'DllMain' sau đó sẽ không được gọi (cho quá trình tách) miễn là luồng đang chạy. –

5

Không. Bạn không nên gọi CreateThread (hoặc bất kỳ biến đổi nào) từ DllMain. Cố gắng đồng bộ hóa sẽ dẫn đến bế tắc. Chính xác những gì bạn đang cố gắng để làm?

Best Practices for Creating DLLs

+7

Không có gì sai với việc gọi CreateThread, nhưng không có cách nào xung quanh thực tế là các chủ đề sẽ bị đình chỉ cho đến khi xử lý DllMain hoàn thành trong chuỗi phụ huynh. –

0

Bạn đang gặp rắc rối nếu bạn làm điều này. Bạn không nên thực hiện bất kỳ cuộc gọi nào (trực tiếp hoặc gián tiếp) với các chức năng nằm ngoài dll của bạn (bao gồm cả các cuộc gọi thư viện C, v.v.).

Nếu bạn không thể thay đổi DLL bạn có (ví dụ bạn không có mã nguồn), bạn có thể có thể thoát khỏi điều này nếu DLL của bạn được tải động sau khi phần còn lại của DLL phụ thuộc của bạn được khởi tạo. Tôi sẽ không khuyên bạn nên tiếp cận này nếu bạn có thể tránh nó bởi vì tìm ra chuỗi phụ thuộc không phải luôn luôn tầm thường (ví dụ: nếu dll của bạn gây ra một dll phụ thuộc để tải một thứ ba động thông qua COM hoặc một số phương tiện khác).

+2

Đoạn đầu tiên ở đây là một quá khái quát. Nó hoàn toàn tốt để thực hiện cuộc gọi vào các tệp DLL mà bạn biết cho một thực tế đã được tải trước của bạn. Nói chung và trong hầu hết các trường hợp, điều này có nghĩa là chỉ KERNEL32.DLL, có thể nghe như một giới hạn làm tê liệt, nhưng bạn có thể sử dụng nó để khởi động theo cách của bạn trong tình huống này. –

+2

http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx –

+0

Cảm ơn Nhà thơ số nguyên. Điều đó trả lời chính xác câu hỏi tôi đến đây để giải quyết. –

5

Chủ đề của bạn làm gì?

Nếu bạn đang cố gắng di chuyển nội dung vào chuỗi thứ hai để tránh những hạn chế về những gì bạn có thể làm bên trong DllMain, may mắn khó khăn. Đó không phải là những hạn chế về những gì DllMain có thể làm, chúng là những hạn chế về những gì có thể được thực hiện trong khi DllMain đang chạy (và giữ khóa bộ nạp). Nếu chủ đề của bạn cần lấy khóa bộ nạp, nó sẽ đợi cho đến khi luồng đầu tiên kết thúc bằng cách sử dụng nó. Nếu chủ đề của bạn không cần khóa bộ nạp, tôi không thấy lý do tại sao nó không thể tiếp tục ngay lập tức ... nhưng không có thứ gì như một luồng không cần khóa bộ nạp. Windows phải gửi các tin nhắn DLL_THREAD_ATTACH đến tất cả các tệp DLL trước khi chuỗi của bạn có thể bắt đầu chạy, điều đó có nghĩa là nó cũng gọi DllMain của riêng bạn và Windows bảo vệ chống lại sự ủy nhiệm lại.

Không còn cách nào khác. Chủ đề không thể bắt đầu cho đến sau khi xử lý DLL_THREAD_ATTACH và điều đó không thể xảy ra trong khi chuỗi đầu tiên của bạn nằm trong DllMain. Cách duy nhất có thể xung quanh nó là để bắt đầu một quá trình mới (trong đó có một khóa tải độc lập và sẽ không chặn chờ đợi cho bạn).

+0

Tôi đã thử một bài tập đơn giản bằng cách sử dụng 'CreateThread()' cho một hàm nhân công rất đơn giản trong một 'DLLMain()' trong khi xử lý một thông báo 'DLL_PROCESS_ATTACH'. Hàm thread sử dụng 'Sleep()' trong 1000 mili giây. Mọi thứ đều ổn. Tôi có thể thấy các tin nhắn 'DLL_THREAD_ATTACH' và' DLL_THREAD_DETACH' từ cả chuỗi ban đầu đang thực hiện 'DLL_PROCESS_ATTACH' và chuỗi được tạo trong quá trình đính kèm. Tuy nhiên chuỗi công nhân này không có gì khác ngoài 'Sleep()'. Các cuộc gọi Kernel32.dll được cho là tốt. Thử nghiệm với VS 2005 Windows 7. –

+0

Rất kỳ lạ, đây thực sự là câu trả lời duy nhất giải quyết được câu hỏi đã được hỏi. Tôi không biết tại sao OP quyết định chấp nhận một câu trả lời không phải. – IInspectable