2009-09-08 44 views
8

Tôi có một chương trình phải thực hiện các tác vụ nhất định trước khi kết thúc. Vấn đề là đôi khi chương trình bị treo với một ngoại lệ (như cơ sở dữ liệu không thể đạt được, vv). Bây giờ, có cách nào để phát hiện một chấm dứt bất thường và thực hiện một số mã trước khi nó chết không?phát hiện chấm dứt chương trình (C, Windows)

Cảm ơn.

mã được đánh giá cao.

+0

Sử dụng bộ xử lý tín hiệu SIGSEGV. ;-) –

Trả lời

9

1. Win32

Các Win32 API chứa một cách để thực hiện điều này thông qua SetUnhandledExceptionFilter chức năng như sau:

LONG myFunc(LPEXCEPTION_POINTERS p) 
{ 
    printf("Exception!!!\n");  
    return EXCEPTION_EXECUTE_HANDLER; 
} 

int main() 
{ 
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&myFunc);  
    // generate an exception ! 
    int x = 0; 
    int y = 1/x; 
    return 0; 
} 

2. POSIX/Linux

Tôi thường thực hiện điều này thông qua chức năng signal() và sau đó xử lý tín hiệu SIGSEGV một cách thích hợp. Bạn cũng có thể xử lý tín hiệu SIGTERM và SIGINT, nhưng không thể xử lý SIGKILL (theo thiết kế). Bạn có thể sử dụng strace() để có được một backtrace để xem những gì gây ra tín hiệu.

+4

Ngoài ra, về bạn bình luận về TerminateProcess() ... câu trả lời đơn giản là bạn không thể làm bất cứ điều gì sau khi TerminateProcess() được gọi cho quá trình của bạn. Đừng qua đời, đừng thu 200 đô la. Quá trình của bạn thoát, ngay bây giờ. Giai đoạn. Kết thúc. – cigarman

+0

Cảm ơn các ý kiến. Vấn đề không phải là ngoại lệ. Vấn đề là phát hiện sự cố hoặc cuộc gọi chấm dứt. Trường hợp ngoại lệ tôi có thể xử lý đã – wonderer

+0

Đó là những gì SetUnhandledExceptionFilter làm, nó xử lý "sự cố" như tràn ngăn xếp, truy cập bộ nhớ null, v.v. Nó không chỉ là một trình xử lý ngoại lệ trong ý thức try/catch. – cigarman

1

Nếu đó là Windows-chỉ, sau đó bạn có thể sử dụng SEH (SetUnhandledExceptionFilter), hoặc VEH (AddVectoredExceptionHandler, nhưng nó chỉ cho XP/2003 trở lên)

+0

tôi nghĩ điều này có thể hữu ích. bạn có đoạn mã mẫu không? – wonderer

+0

http://codepad.org/mUAUB25D - nhưng đó là cách đơn giản nhất, có nhiều trình xử lý sự cố phức tạp hơn trên mạng (ví dụ: trên CodeProject). –

+0

Tôi đã thử, nó có vẻ tốt nhưng tôi nếu tôi giết quá trình (từ người quản lý tác vụ, vv) nó không phát hiện ra nó. – wonderer

2

Nó phụ thuộc bạn làm gì với "ngoại lệ" của bạn. Nếu bạn xử lý chúng đúng cách và thoát khỏi chương trình, bạn có thể đăng ký chức năng của bạn để được gọi khi thoát, sử dụng atexit().

Nó sẽ không hoạt động trong trường hợp chấm dứt bất thường thực sự, như segfault.

Không biết về Windows, nhưng trên hệ điều hành tuân thủ POSIX, bạn có thể cài đặt trình xử lý tín hiệu sẽ bắt các tín hiệu khác nhau và thực hiện điều gì đó về nó. Tất nhiên bạn không thể bắt được SIGKILLSIGSTOP.

API tín hiệu là một phần của ANSI C kể từ C89 vì vậy có lẽ Windows hỗ trợ nó. Xem signal() syscall để biết chi tiết.

+0

có ... Tôi cần để có thể phát hiện một kết thúc bình thường và bất thường ... – wonderer

+0

Tôi đang sử dụng một cái gì đó tương tự như bắt ctrl-c và các tín hiệu chấm dứt khác nhưng tôi không thể bắt một TerminateProcess. Nếu tôi nhớ chính xác bạn không thể dừng SIGKILL, điều tương tự cũng áp dụng cho TerminateProcess. Nó chỉ làm cho ứng dụng chết. – wonderer

0

Xin lỗi, không phải là lập trình viên cửa sổ. Nhưng có thể

_onexit() 

Đăng ký một chức năng được gọi khi chương trình chấm dứt.

http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx

+0

Đó là C++, không phải C. –

+0

cảm ơn nhưng nó không thực sự hữu ích. Tôi có thể bị chấm dứt bình thường. – wonderer

0

Thứ nhất, mặc dù điều này là khá rõ ràng: Bạn không bao giờ có thể có một giải pháp hoàn toàn mạnh mẽ - một người nào đó luôn có thể chỉ cần nhấn cáp điện để chấm dứt quá trình của bạn. Vì vậy, bạn cần một sự thỏa hiệp, và bạn cần phải cẩn thận đặt ra các chi tiết của thỏa hiệp đó.

Một trong những giải pháp mạnh mẽ hơn là đưa mã có liên quan vào chương trình trình bao bọc. Chương trình bao bọc gọi chương trình "thực" của bạn, chờ quá trình chấm dứt, và sau đó - trừ khi chương trình "thực" của bạn đặc biệt báo hiệu rằng nó đã hoàn thành bình thường - chạy mã dọn dẹp. Điều này là khá phổ biến cho những thứ như khai thác thử nghiệm, nơi mà các chương trình thử nghiệm có khả năng sụp đổ hoặc hủy bỏ hoặc nếu không chết theo những cách bất ngờ.

Điều đó vẫn mang lại cho bạn những khó khăn của những gì sẽ xảy ra nếu ai đó thực hiện một TerminateProcess trên hàm bao bọc của bạn, nếu đó là điều bạn cần phải lo lắng. Nếu cần thiết, bạn có thể giải quyết vấn đề này bằng cách thiết lập nó như một dịch vụ trong Windows và sử dụng các tính năng của hệ điều hành để khởi động lại nó nếu nó chết. (Điều này chỉ thay đổi mọi thứ một chút, ai đó vẫn có thể dừng dịch vụ.) Tại thời điểm này, bạn có thể đang ở thời điểm bạn cần báo hiệu thành công bằng một thứ gì đó liên tục như tạo tệp.

+0

Tôi đồng ý với bạn. Vấn đề chính của tôi là thực hiện một hành động cuối cùng trước khi chết tại một TerminateProcess hoặc sự kiện không lường trước được. Phần còn lại của sự kiện được thực hiện. Tôi đã nói chuyện với người phụ trách dự án về việc chuyển đổi ứng dụng giám sát thành một dịch vụ nhưng đó là không. Tôi đoán không có cách nào để làm điều này ... – wonderer

5

sysinternals forum threads về bảo vệ chống lại các nỗ lực kết thúc bằng cách gắn NT Internals, nhưng những gì bạn thực sự muốn là một cơ quan giám sát hoặc ngang hàng (cách tiếp cận hợp lý) hoặc một số phương pháp ngăn chặn các sự kiện thảm khốc (khá dicey).

Chỉnh sửa: Có những lý do khiến chúng gây khó khăn, nhưng có thể chặn hoặc chặn các nỗ lực để giết quá trình của bạn.Tôi biết bạn chỉ đang cố gắng dọn dẹp trước khi xuất cảnh, nhưng ngay sau khi ai đó giải phóng một quá trình mà không thể bị giết ngay lập tức, ai đó sẽ yêu cầu một phương pháp để giết nó ngay lập tức, và cứ thế. Nhưng dù sao, để đi xuống con đường này, hãy xem chuỗi liên kết ở trên và tìm kiếm một số từ khóa bạn tìm thấy ở đó để biết thêm. móc HOẶC bộ lọc NtTerminateProcess vv Chúng tôi đang nói về mã hạt nhân, trình điều khiển thiết bị, chống vi-rút, bảo mật, phần mềm độc hại, công cụ rootkit tại đây. Một số sách để trợ giúp trong lĩnh vực này là Windows NT/2000 Native API, Undocumented Windows 2000 Secrets: A Programmer's Cookbook, Rootkits: Subverting the Windows Kernel và, tất nhiên, Windows® Internals: Fifth Edition. Công cụ này không quá khó để viết mã, nhưng khá nhạy cảm để có được đúng, và bạn có thể giới thiệu các tác dụng phụ không mong muốn.

Có lẽ Application Recovery and Restart Functions có thể được sử dụng? Được hỗ trợ bởi Vista và Server 2008 trở lên.

ApplicationRecoveryCallback Callback Function ứng dụng xác định hàm callback dùng để lưu dữ liệu và thông tin trạng thái ứng dụng trong trường hợp việc áp dụng gặp phải một ngoại lệ unhandled hoặc trở nên không phản hồi.

Về việc sử dụng SetUnhandledExceptionFilter, MSDN Social discussion khuyên rằng để làm cho công việc này đáng tin cậy, vá phương pháp mà trong bộ nhớ là cách duy nhất để chắc chắn rằng bộ lọc của bạn được gọi. Thay vào đó nên thay thế bằng __try/__ ngoại trừ. Bất kể, có một số mã mẫu và thảo luận về lọc các cuộc gọi tới SetUnhandledExceptionFilter trong bài viết "SetUnhandledExceptionFilter" and VC8.

Ngoài ra, hãy xem Windows SEH Revisited tại The Factor tuyệt vời cho một số mã mẫu của AddVectoredExceptionHandler.

+0

cảm ơn. Tôi đã thấy những điều đó trước đây. có 2 vấn đề, tho. 1) Tôi phải hỗ trợ XP. 2) Tôi không cần phục hồi sau vụ tai nạn. Tôi chỉ cần lưu một vài tệp và đóng các kết nối db trước khi đóng ứng dụng (hoặc là duyên dáng hoặc trước khi bị lỗi). – wonderer

+0

Gotcha. Đã thêm một số thông tin và liên kết đến mã mẫu và thảo luận về SUEF và AVEH. –

+0

hãy để tôi thử điều này. Tuy nhiên, tôi không thể bắt được TerminateProcess. Từ những gì tôi thấy điều này là không thể – wonderer

0

Tôi đã xuất bản một bài viết tại ddj.com về "gỡ lỗi bản thân bài đăng" vài năm trước.

Nó bao gồm các nguồn cho cửa sổ và unix/linux để phát hiện chấm dứt bất thường. Theo kinh nghiệm của tôi, một trình xử lý cửa sổ được cài đặt bằng cách sử dụng SetUnhandledExceptionFilter là không phải lúc nào cũng được gọi là. Trong nhiều trường hợp, nó được gọi, nhưng tôi nhận được khá nhiều tệp nhật ký từ khách hàng không bao gồm báo cáo từ các trình xử lý đã cài đặt, tức là một NGUYÊN NHÂN VI PHẠM là nguyên nhân.

http://www.ddj.com/development-tools/185300443

+0

cảm ơn. vấn đề của tôi tho là ngoại lệ nóng. – wonderer

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