2012-03-18 18 views
33

C++ 11 giới thiệu một cách hoàn thành chương trình mới - std::quick_exit.Sự khác nhau giữa std :: quick_exit và std :: abort và lý do std :: quick_exit cần thiết là gì?

Trích dẫn các N3242 18,5 (p 461.):

[[noreturn]] void quick_exit(int status) noexcept; 

Effects: Chức năng đăng ký bởi các cuộc gọi đến at_quick_exit được gọi là theo thứ tự ngược lại đăng ký của họ, ngoại trừ một hàm sẽ được gọi là sau khi bất kỳ chức năng nào đã đăng ký trước đó đã có đã được gọi vào thời điểm được đăng ký. Các đối tượng không được bị hủy do gọi số quick_exit. Nếu điều khiển để lại một hàm đã đăng ký được gọi là quick_exit vì hàm này không cung cấp trình xử lý cho một ngoại lệ được ném, hãy gọi terminate(). [Lưu ý: at_quick_exit có thể gọi chức năng đã đăng ký từ một chủ đề khác nhau so với đăng ký nó, vì vậy chức năng đã đăng ký phải không dựa vào danh tính đối tượng có thời lượng lưu trữ luồng. - lưu ý cuối cùng] Sau khi gọi các chức năng đã đăng ký, quick_exit sẽ gọi _Exit(status). [Lưu ý: Bộ đệm tệp chuẩn không bị xóa. Xem: ISO C 7.20.4.4. - cuối note]

Như định nghĩa của std::abort(void)std::_Exit(int status) chỉ khác nhau ở khả năng để vượt qua tình trạng để quá trình cha mẹ, nó làm tăng câu hỏi của tôi.

Liệu nó có nghĩa là sự khác biệt duy trong ngữ nghĩa giữa std::quick_exitstd::abort là rằng std::quick_exit cuộc gọi chức năng đăng ký sử dụng std::at_quick_exit và cho phép để thiết lập tình trạng trả lại?

Lý do để giới thiệu chức năng này là gì?

Trả lời

34

Có một tốt write-up available here, tôi sẽ chỉ tóm tắt nó. Tính năng này đã được thêm vào để xử lý cụ thể với độ khó của việc kết thúc chương trình một cách sạch sẽ khi bạn sử dụng chuỗi. Theo tự nhiên, lối ra được bắt đầu bởi một sự kiện không đồng bộ cao, người dùng đóng giao diện người dùng, quản trị tắt máy, v.v. Điều này xảy ra mà không liên quan đến trạng thái của các chủ đề mà chương trình bắt đầu, chúng hầu như luôn ở trạng thái không thể đoán trước được. Trong một thế giới lý tưởng, hàm main() của chương trình yêu cầu các luồng thoát ra, thường là bằng cách báo hiệu một sự kiện, đợi các luồng kết thúc và sau đó thoát khỏi chính() để tắt máy sạch thông qua exit(). Tuy nhiên, lý tưởng đó là rất khó đạt được. Một sợi có thể được chôn sâu bên trong một cuộc gọi hệ thống, nói, chờ đợi một số I/O để hoàn thành. Hoặc nó đang chặn trên một đối tượng đồng bộ hóa cần phải được báo hiệu bởi một luồng khác theo đúng thứ tự. Kết quả là hiếm khi dễ chịu, chương trình thực sự thường bế tắc khi xuất cảnh. Hoặc sụp đổ khi lệnh tắt máy là bất ngờ.

Có cách giải quyết đơn giản và rất hấp dẫn cho vấn đề này: gọi _exit() thay thế. Kaboom, chương trình kết thúc, hệ điều hành chổi lên mảnh đạn. Nhưng rõ ràng mà không có bất kỳ dọn dẹp ở tất cả, đôi khi rất lộn xộn với hiện vật như một tập tin một nửa hoặc một giao dịch dbase không đầy đủ.

std :: quick_exit() cung cấp giải pháp thay thế. Tương tự như _exit() nhưng vẫn có tùy chọn để thực hiện một số mã, bất kỳ mã nào được đăng ký với at_quick_exit.

+5

Ngoài ra, vì 'abort' signal' SIGABRT', gọi 'abort' sẽ thường dẫn đến kết quả (mặc dù có thể cấu hình được) trong * * core dump ** trên * nix, hoặc trong cửa sổ bật lên trên Windows (ví dụ: _Program đã ngừng hoạt động, Close/Debug_) Chỉ sử dụng 'abort' khi chấm dứt do điều kiện ** không mong muốn ** và bạn muốn một coredump/minidump để ** chẩn đoán lý do ** cho điều kiện bất ngờ. – vladr

2

std::abort sẽ chấm dứt ứng dụng của bạn mà không cần gọi bất kỳ chức năng nào được đăng ký sử dụng "at_exit/at_quick_exit". Mặt khác, std::quick_exit sẽ, như bạn đã chỉ ra, hãy gọi các chức năng đã đăng ký sử dụng std::at_quick_exit.

std::abort thường là hủy bỏ ứng dụng của bạn, điều này sẽ được gọi khi xảy ra tình huống bất thường và ứng dụng của bạn phải đóng mà không thực hiện bất kỳ hoạt động dọn dẹp nào. Từ các tài liệu std::abort:

Nguyên nhân bất thường chấm dứt chương trình trừ SIGABRT đang được đánh bắt bằng một xử lý tín hiệu thông qua để báo hiệu và xử lý không trả lại.

Khi bạn muốn thực hiện một số lần dọn dẹp, std::quick_exit sẽ thuận tiện hơn. Chức năng cuối cùng này cũng cho phép bạn dừng ứng dụng của mình một cách duyên dáng, vì nó kết thúc bằng cách gọi std::_Exit thay vì báo hiệu tín hiệu như std::abort (tín hiệu SIGABRT, khiến ứng dụng dừng bất thường).

std::exit cho phép bạn thoát khỏi ứng dụng của bạn một cách duyên dáng, trong khi vẫn làm sạch các biến số địa phương và tĩnh tự động, luồng. std::quick_exit thì không.Đó là lý do tại sao có một "quick_" trong tên của nó, nó nhanh hơn kể từ khi nó bỏ qua giai đoạn làm sạch.

Do đó, có sự khác biệt ngữ nghĩa thực tế giữa hai hàm. Người ta dừng ứng dụng một cách bất thường, và người kia thực hiện một lối thoát duyên dáng, cho phép bạn làm một số việc dọn dẹp.

+1

Và điều đó vẫn chưa được giải quyết - tại sao cho phép làm một số dọn dẹp và không phải tất cả, khi chấm dứt được thực hiện "duyên dáng"? Tôi chưa bao giờ thấy 'quick_exit' trong một mã thực sự, nhưng nếu tôi nhận được nó trong việc xem xét mã, tôi muốn, có lẽ, bị cám dỗ để yêu cầu làm cho nó hoàn thành dọn dẹp hoặc không có gì. Có bất kỳ nguồn WG21 nào về điều này không? –

+0

Nếu bạn muốn dọn dẹp hoàn toàn, sau đó bạn sẽ sử dụng "thoát". quick_exit nhanh hơn, vì nó không gọi bất kỳ desctructor biến tự động, địa phương và tĩnh. Tôi tin rằng nó sẽ là tốt hơn để so sánh std :: quick_exit với std :: exit, vì cả hai đều cho phép người dùng thực hiện một đóng gracefull, trong khi std :: abort về cơ bản chấm dứt ứng dụng của bạn bất thường. – mfontanini

+5

C + + destructors thường làm những việc (như bộ nhớ miễn phí) mà không cần thiết khi quá trình này là thoát (vì hệ điều hành sẽ làm điều đó). Tôi đoán rằng 'quick_exit' cho phép bạn làm một số dọn dẹp, nhưng để phần còn lại cho hệ điều hành. –

19

Lý do cho std::quick_exit được thảo luận trong N1327N2440. Sự khác biệt chính giữa quick_exit, _Exit, và exit lo ngại việc xử lý Destructor tĩnh và xả nước thông tin quan trọng để lưu trữ ổn định:

  • std::_Exit: không thực hiện hủy tĩnh hoặc tuôn ra quan trọng IO.
  • std::exit: thực hiện các trình phá hủy tĩnh và xóa sạch IO quan trọng.
  • std::quick_exit: không thực thi các trình phá hủy tĩnh, nhưng thực hiện xóa IO quan trọng.

(Như đã đề cập, std::abort chỉ gửi SIGABRT.)

+2

Tôi không thấy bất kỳ bằng chứng nào trong tiêu chuẩn rằng std :: quick_exit xóa IO quan trọng. Trong thực tế, tiêu chuẩn nói "Lưu ý: Bộ đệm tệp tiêu chuẩn không bị xóa." Cơ sở cho niềm tin của bạn rằng std :: quick_exit flushes IO quan trọng là gì, và, cho rằng vấn đề, những gì bạn có nghĩa là bởi "quan trọng" IO? – KnowItAllWannabe

+2

@KnowItAllWannabe: Anh ấy xác định quan trọng là "bạn quan tâm đủ để đăng ký trình xử lý' at_quick_exit': –

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