2009-01-20 37 views
5

Làm thế nào tôi có thể đảm bảo một dll không được giải phóng trong khi bất kỳ đối tượng nào tồn tại?C++: Vấn đề tải Dll

Vấn đề là khi tôi sử dụng trình quản lý bộ nhớ, tôi có thể xóa các đối tượng dll trước khi giải phóng dll, tuy nhiên với con trỏ thông minh, tôi không có quyền kiểm soát thứ tự bị hủy, nghĩa là dll có thể được giải phóng trước. khi cố gắng để giải phóng một trong những đối tượng khác:

FlPtr là một thats đơn giản lớp refrence đếm gọi AddRef và Thả khi cần thiết

ExampleDll *dll = LoadDll(L"bin\\example.dll"); 
IObject *obj = dll->CreateObject(); 
... 
obj->Release(); 
delete dll;//fine because all objects already deleted 
return 0; 

auto_ptr<ExampleDll> dll = LoadDll(L"bin\\example.dll"); 
FlPtr<IObject> obj = dll->CreateObject(); 
... 
return 0;//crash if dll is destructed before obj since Object::Release needs to call into the dll 

tôi đã cố gắng làm cho tay cầm dll dỡ itsself, tức là chỉ dỡ bỏ sau khi tất cả đối tượng đã bị xóa. Công việc này bằng cách tạo một đối tượng mới IExampleDll mà dll thực hiện. Điều này giống như đối tượng ExampleDll từ trước nhưng sống trong dll thay vì exe và cũng được tính đếm. Mỗi đối tượng trong dll gia tăng này refrence trên contruction và deincrements nó về tiêu hủy. Điều này có nghĩa là số lượng refrence chỉ đạt đến số không khi exe đã phát hành refrences của nó và tất cả các đối tượng dlls đã bị phá hủy. Sau đó nó xóa selfself của nó gọi FreeLibrary (GetModuleHandle()) trong destructor của nó.

Tuy nhiên điều này treo tại FreeLibrary, im asuming vì thread vẫn còn trong mã dlls đang được bốc dỡ ...

Tôi đang ở một mất mát hiện nay như thế nào để đảm bảo dll chỉ bốc dỡ khi không có các đối tượng còn lại, ngoài việc quay lại để giải phóng dll một cách rõ ràng sau khi mọi thứ khác đáng lẽ phải bị xóa;

int main() 
{ 
    ExampleDll *dll = LoadDll("bin\\example.dll"); 
    restOfProgram(); 
    delete dll; 
} 

Phương pháp này trở nên khó khăn khi dll cần được tải/dỡ tải giữa chương trình, tức là nếu người dùng thay đổi từ d3d sang openGL trong tùy chọn.

Trả lời

6

Giả sử bạn không muốn chấm dứt chuỗi khi dỡ thư viện (nếu không, xem MSalters), bạn cần giải phóng thư viện khỏi người gọi đã tải nó. COM2 giải quyết rằng bởi một bộ đếm thể hiện trong DLL (giống như của bạn, nếu tôi hiểu bạn một cách chính xác), và kiểm tra nó bằng cách gọi hàm toàn cầu xuất khẩu CanUnloadNow.

Một tùy chọn khác là có đối tượng/giao diện con trỏ thông minh của bạn CSONG tham chiếu đến DLL mà chúng xuất phát. Điều này sẽ làm tăng kích thước dữ liệu khách hàng, nhưng bạn sẽ không cần phải chạm vào DLL. Bạn thậm chí có thể tái chế bộ đếm tham chiếu LoadLibrary/FreeLibrary, tuy nhiên nó có thể đạt hiệu năng.

Ngoài ra, không có sơ đồ nào trong số này giúp ích nhiều nếu bạn nhận phụ thuộc DLL vòng tròn (tham chiếu thành phần DllA.X DllB.Y, tham chiếu DllA.Z). Tôi chưa có một giải pháp tốt cho điều đó mà không đòi hỏi kiến ​​thức toàn cầu.

+0

Ok Tôi đã có một suy nghĩ, nếu các dlls Release() phương pháp trả lại một bool, sai nếu không có refrences còn lại, một đặc biệt DllPtr có thể gọi thư viện miễn phí nếu phát hành trả lại false –

+0

Nhưng vẫn còn có vấn đề cuối cùng refrence bị xóa trong dll nếu DllPtr của bị xóa đầu tiên ... Làm thế nào tôi sẽ đi về thực hiện các phương pháp tiếp cận COM vì vậy tôi có thể tiếp tục thăm dò ý kiến ​​các dll sau khi ngăn xếp và tĩnh (tức là globals) bị phá hủy vì chỉ sau đó là nó garunteed có không ref? –

+0

Bạn sẽ cần một loại "sạch" đối tượng mà không phải là trong dll mà bạn đang bốc dỡ để dỡ thành công dll như vậy, đây là khoảng những gì ole32.dll không khi CoUnitialize được gọi là. – Ismael

0

MSDN là rõ ràng về chủ đề này:.. "Một chủ đề mà phải dỡ bỏ các DLL trong đó nó được thực hiện và sau đó chấm dứt bản thân nên gọi FreeLibraryAndExitThread thay vì gọi FreeLibraryExitThread riêng Nếu không, một điều kiện chủng tộc có thể xảy ra Để biết chi tiết, xem các chú thích phần của FreeLibraryAndExitThread

+0

Tôi không muốn chấm dứt chuỗi, chỉ cần giải phóng dll và quay lại tệp exe/previous dll –

+0

Điều đó không có ý nghĩa - bạn vừa hủy tất cả các câu lệnh trả về! – MSalters

1

đối với trường hợp các DLL được bật tại thời gian chạy, tôi muốn tránh những hệ thống con trỏ thông minh cho các đối tượng được tạo ra bởi các DLL và sử dụng một hệ thống như thế này:.

    |-----------------------| |--------------------------| 
        | Abstraction Interface | | Implementation Interface | 
        |-----------------------| |--------------------------| 
          ^      ^
           |       | 
|-------------|1  *|-------------------|*  *|----------------| 
| Application |-------| Abstraction Layer |--------| Implementation | 
|-------------|  |-------------------|  |----------------| 

\------------- Main Program ------------------/ \-------- DLL --------/ 

Ứng dụng này chứa danh sách tất cả alloca các đối tượng lớp trừu tượng ted. Các đối tượng lớp trừu tượng là các đối tượng duy nhất được phép sở hữu con trỏ tới các đối tượng được tạo bởi lớp triển khai. Khi hoán đổi các tệp DLL, trước tiên hãy lặp lại tất cả các đối tượng lớp trừu tượng và yêu cầu chúng giải phóng dữ liệu cụ thể thực hiện. Sau đó unload DLL và tải DLL mới. Sau đó, lặp lại các đối tượng lớp trừu tượng một lần nữa và yêu cầu họ tạo dữ liệu cụ thể triển khai mới.

0

Ok tôi nghĩ rằng sự lựa chọn tốt nhất là sử dụng phương pháp COM để thăm dò ý kiến ​​của dll để xem liệu nó có thể được dỡ xuống hay không. Làm thế nào tôi có thể đi về làm điều này mặc dù để tôi có thể tiếp tục bỏ phiếu các dll sau khi mọi thứ khác đã đóng cửa (tức là chủ đề chính đã chấm dứt)? Tôi có cần phải tạo ra một quá trình riêng biệt hoàn toàn để làm điều này, trong trường hợp này làm thế nào để tôi làm điều đó để quá trình riêng biệt này biết về tất cả các dll được nạp, và theo cách có tác động rất ít đến proformance?

Mayby Tôi chỉ có thể tạo hệ thống bỏ phiếu khi tất cả các DllPtr nằm ngoài phạm vi và chấm dứt nó ngay sau khi nó có dll miễn phí? Bằng cách đó, nó chỉ tồn tại miễn là nó mất cho bất kỳ con trỏ thông minh remaing bị phá hủy.