2009-05-27 71 views
10

Có nhiều cách khác nhau để thoát khỏi quy trình:Các cách thoát khác nhau của quy trình trong C++

ví dụ: ExitProcess, ExitThread (từ chủ đề chính), thoát, hủy, trả về từ chính, chấm dứt.

Tôi muốn biết các hiệu ứng của từng phương pháp có đối với việc hủy đối tượng tĩnh/toàn cầu/tự động.

Ví dụ, tôi có một dự án bị treo (có thể do một số lỗi deallocation) khi ExitProcess được gọi, nhưng không phải khi exit() được gọi. (liên quan đến this question, tình cờ).

Vì vậy, về cơ bản, tôi muốn biết trong trường hợp nào việc giải quyết các đối tượng trên xảy ra và theo thứ tự nào (Đối với VC++).

Trả lời

14

Tóm tắt: Điều hoàn toàn an toàn cần làm là cho phép main() hoặc chức năng chuỗi của bạn, tới return.

C++ đảm bảo tiêu chuẩn (3.6.3/1, 18,3) mà destructors cho các đối tượng toàn cầu (bao gồm cả đối tượng tĩnh) sẽ được gọi nếu exit() được gọi, tuy nhiên nó khẳng định một cách rõ ràng rằng destructors cho địa phương biến sẽ không được gọi trong trường hợp này. exit() sẽ gọi bất kỳ chức năng nào được đăng ký với atexit(), và cũng sẽ tuôn ra và sau đó đóng bất kỳ luồng stdio mở nào (bao gồm ít nhất stdin, stdout, stderr).

Gọi số abort() được đảm bảo không gọi cho người phá hoại địa phương hoặc toàn cầu. Nó cũng sẽ không gọi hàm được đăng ký với atexit() hoặc các luồng stdio tuôn ra.

Calling bất kỳ Win32 nguyên thủy như ExitProcess() hoặc ExitThread() chắc chắn sẽ không gọi destructors cho các biến địa phương, và gần như chắc chắn không gọi bất kỳ destructors cho các đối tượng toàn cầu, hay bất kỳ chức năng đăng ký với atexit(). Gọi các chức năng này trực tiếp trong chương trình C++ không được thông báo - về cơ bản, các hàm Win32 này và thư viện thời gian chạy C++ không biết gì về nhau. Trong thực tế, ngay cả các MSDN documentation for ExitThread() khuyên rằng các chương trình C++ nên trở về từ chức năng thread thay vì gọi ExitThread().

(Về mặt lý thuyết có thể thư viện thời gian chạy đã được sắp xếp đặc biệt cho ExitProcess() để gọi hàm hủy đối tượng toàn cầu - điều này có thể được thực hiện bằng cách luôn tải một DLL cụ thể mà chức năng điểm nhập sẽ thực hiện các cuộc gọi này, kể từ ExitProcess() chức năng điểm cho mỗi DLL được nạp với DLL_PROCESS_DETACH - tuy nhiên để hiểu biết của tôi, không có thực hiện điều này)

+5

trên thực tế ExitProcess không gọi atexit đăng ký. destructors toàn cầu, nếu chúng được định nghĩa trong một DLL. Nó phụ thuộc vào thứ tự của các cuộc gọi đến DLLMain (tách quy trình). ExitProcess dường như loại bỏ các tệp DLL đầu tiên và sau đó cố gắng dọn sạch các giá trị riêng của nó và thoát() làm điều ngược lại. Vì vậy, nếu bạn khai báo các statics dựa vào một số DLL bên ngoài, chúng có thể không bị phá hủy thông qua ExitProcess. (Điều này dựa trên một số thử nghiệm tôi đã thực hiện hôm nay.) –

+0

Thú vị là các DLL khác dường như gọi hàm hủy của chúng khi chúng nhận được DLL_PROCESS_DETACH.Các tài liệu cho ExitProcess() không nói theo thứ tự các điểm nhập của DLL được gọi, nhưng ngay cả khi chúng được gọi theo thứ tự LIFO, tôi nghĩ rằng các vấn đề vẫn có thể phát sinh nếu các đối tượng toàn cầu trong các DLL khác nhau tham chiếu lẫn nhau. –

+1

Gọi dtors từ DLL_PROCESS_DETACH có ý nghĩa nếu bạn nhận thấy họ gọi ctors từ DLL_PROCESS_ATTACH. Nhưng nó thực sự lên đến trình biên dịch mà tạo ra các DLL và người gọi để sắp xếp này. Nhìn vào DLL tải lười biếng để xem một con đường thực hiện có thể. – MSalters

-3

Xem mã nguồn của ExitProcess() (được đăng trên CompuServe, usenet)

+0

Cám dỗ -1 điều này - nếu có thể, bạn nên tránh tùy thuộc vào chi tiết triển khai vì chúng có thể thay đổi mà không cần thông báo bất kỳ lúc nào ** (ví dụ: khi quá trình nền Windows Update tiếp theo cài đặt bản cập nhật bảo mật) . Điều đó nói rằng, nếu bạn biết chắc chắn rằng mã nguồn tương ứng với phiên bản bạn đang chạy, điều này có thể giúp bạn gỡ lỗi một cái gì đó. –

Các vấn đề liên quan