Tại sao Môi trường.Exit () không chấm dứt chương trình nữa?


134

Đây là điều tôi phát hiện ra cách đây vài ngày, tôi đã xác nhận rằng nó không chỉ giới hạn trong máy của tôi từ câu hỏi này .

Cách dễ nhất để repro nó là bắt đầu một ứng dụng Windows Forms, thêm một nút và viết mã này:

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("yada");
        Environment.Exit(1);         // Kaboom!
    }

Chương trình thất bại sau khi câu lệnh Exit () thực thi. Trên Windows Forms, bạn nhận được "Lỗi khi xử lý cửa sổ".

Kích hoạt gỡ lỗi không được quản lý làm cho nó phần nào rõ ràng những gì đang xảy ra. Các COM loop phương thức được thực hiện và cho phép một thông điệp WM_PAINT sẽ được chuyển giao. Đó là gây tử vong trên một hình thức xử lý.

Sự thật duy nhất tôi đã thu thập được cho đến nay là:

  • Nó không chỉ giới hạn để chạy với trình gỡ lỗi. Điều này cũng thất bại mà không có một. Cũng khá kém, hộp thoại sự cố WER xuất hiện hai lần .
  • Nó không có gì để làm với bitness của quá trình. Lớp wow64 khá nổi tiếng, nhưng bản dựng AnyCPU gặp sự cố theo cách tương tự.
  • Nó không có gì để làm với phiên bản .NET, 4.5 và 3.5 bị lỗi theo cùng một cách.
  • Mã thoát không thành vấn đề.
  • Gọi Thread.S ngủ () trước khi gọi Thoát () không khắc phục được.
  • Điều này xảy ra trên phiên bản 64 bit của Windows 8 và Windows 7 dường như không bị ảnh hưởng theo cùng một cách.
  • Đây là hành vi tương đối mới, tôi chưa từng thấy điều này trước đây. Tôi thấy không có bản cập nhật liên quan nào được gửi qua Windows Update , mặc dù lịch sử cập nhật không còn chính xác trên máy của tôi nữa.
  • Đây là hành vi phá vỡ thô bạo. Bạn sẽ viết mã như thế này trong một trình xử lý sự kiện cho AppDomain.UnhandledException và nó gặp sự cố theo cách tương tự.

Tôi đặc biệt quan tâm đến những gì bạn có thể làm để tránh sự cố này. Đặc biệt là kịch bản AppDomain.UnhandledException làm tôi bối rối; không có nhiều cách để chấm dứt chương trình .NET. Xin lưu ý rằng việc gọi Application.Exit () hoặc Form.C Đóng () không hợp lệ trong trình xử lý sự kiện cho UnhandledException, vì vậy chúng không phải là cách giải quyết.


CẬP NHẬT: Mehrdad chỉ ra rằng chủ đề hoàn thiện có thể là một phần của vấn đề. Tôi nghĩ rằng tôi đang nhìn thấy điều này và tôi cũng đang thấy một số bằng chứng cho thời gian chờ 2 giây rằng CLR đưa ra chuỗi hoàn thiện để hoàn thành việc thực thi.

Trình hoàn thiện nằm trong NativeWindow.ForceExitMessageLoop (). Có một hàm Win32 IsWindow () tương ứng với vị trí mã, bù 0x3c khi nhìn vào mã máy ở chế độ 32 bit. Có vẻ như IsWindow () đang bế tắc. Tôi không thể có được dấu vết ngăn xếp tốt cho các phần bên trong, tuy nhiên, trình gỡ lỗi nghĩ rằng cuộc gọi P / Gọi vừa được trả về. Điều này thật khó để giải thích. Nếu bạn có thể có được một dấu vết ngăn xếp tốt hơn thì tôi rất muốn nhìn thấy nó. Của tôi

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

Không có gì cao hơn lệnh gọi ForceExitMessageLoop, trình gỡ lỗi không được quản lý được bật.


2
Tôi vừa thử điều này với .NET 4, 4 Client Profile, 3.5, 3.5 Client Profile, 3.0 và 2.0 và không nhận được lỗi nào trong số chúng. Windows 7 64 bit là hệ điều hành của tôi, sử dụng VS2010.
Steve

2
@Steve This happens on the 64-bit version of Windows 8Hans đã nói như vậy!
Parimal Raj

7
Tôi có thể repro cái này (Win 8, 64 bit), sao chép / dán mã của bạn và nối một nút và tôi nhận được các triệu chứng chính xác được mô tả.
bàn

3
Một ứng dụng chế độ bảng điều khiển không thể chứng minh vấn đề này, không có gì có thể sai khi Thoát () tiếp tục bơm tin nhắn.
Hans Passant

3
Tôi đã gặp loại hành vi này với Exit(0)một chút trước đây với một số Win7 64 bit, Thay đổi ExitCodebây giờ không giúp ích gì khi sử dụng Process.GetCurrentProcess().Kill()mà không gặp vấn đề gì
Sriram Sakth Xoay

Câu trả lời:


85

Tôi đã liên lạc với Microsoft về vấn đề này và điều đó dường như đã được đền đáp. Ít nhất tôi muốn nghĩ rằng nó đã làm :). Mặc dù tôi không nhận được xác nhận về độ phân giải từ họ, nhóm Windows rất khó liên hệ trực tiếp và tôi phải sử dụng một trung gian.

Một bản cập nhật được phân phối thông qua Windows Update đã giải quyết vấn đề. Độ trễ 2 giây đáng chú ý trước khi sự cố không còn nữa, cho thấy mạnh mẽ rằng bế tắc IsWindow () đã được giải quyết. Và chương trình tắt sạch và đáng tin cậy. Bản cập nhật đã cài đặt các bản vá cho Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll và wintrust.dll

Uxtheme.dll là con vịt lẻ. Nó triển khai API theo chủ đề Visual Styles và được chương trình thử nghiệm này sử dụng. Tôi không thể chắc chắn, nhưng tiền của tôi là một trong những vấn đề. Bản sao trong C: \ WINDOWS \ system32 có số phiên bản 6.2.9200.16660, được tạo vào ngày 14 tháng 8 năm 2013 trên máy của tôi.

Trường hợp đóng cửa.


11
Lịch sử Windows Update không còn chính xác nữa trên máy của tôi. Tất cả những gì tôi biết là nó đã được cài đặt vào ngày 14 tháng 8.
Hans Passant

51

Tôi không biết tại sao nó không hoạt động "nữa" , nhưng tôi nghĩ rằng Environment.Exitthực thi các quyết toán đang chờ xử lý. Environment.FailFastkhông.

Nó có thể là (vì một số lý do kỳ quái) bạn có những quyết toán chờ xử lý kỳ lạ phải chạy sau đó, khiến điều này xảy ra.


2
Bạn có thể đang ở một cái gì đó. Trình hoàn thiện đang bận thực hiện NativeWindow.ForceExitMessageLoop (). Điều kỳ lạ là nó không được lồng trong bất kỳ cuộc gọi nào.
Hans Passant

@HansPassant: Tôi ước tôi có thể khắc phục vấn đề để tôi có thể xem xét vấn đề này, nhưng tôi không thể. Là cuộc gọi để NativeWindow.ForceExitMessageLoopbị mắc kẹt trong mã được quản lý hoặc không được quản lý? Nó thậm chí còn bị kẹt, hay nó đang bận - chờ đợi hoặc chờ tin nhắn hay cái gì khác?
dùng541686

Điều này chắc chắn dường như chỉ ra vấn đề cốt lõi. Tôi nghĩ rằng đó là hàm winapi IsWindow () là gốc rễ của vấn đề. Tôi nghĩ rằng tôi cũng đang thấy thời gian chờ 2 giây trên chuỗi hoàn thiện, sau đó tất cả biến thành địa ngục. Trình gỡ lỗi không cho thấy nó thực hiện lệnh gọi IsWindow () nhưng tôi đã thấy Windows chơi các thủ thuật với ngăn xếp trước đó, chuyển nó ra khi nhập mã quan trọng vào Windows.
Hans Passant

4
Tôi nghĩ rằng phương thức Môi trường.FailFast (), đối với trường hợp ngoại lệ chưa xử lý, có lẽ là phương pháp tốt nhất để sử dụng. (Tôi không biết về điều đó - cảm ơn!) Tuy nhiên, có rất nhiều mã kế thừa sẽ sử dụng Môi trường .Exit () sẽ bị sập một cách đáng tiếc :(
Ian Yates

2
Bạn chắc chắn nhất về một cái gì đó. Trong trường hợp của tôi, tôi đã bắt đầu một Ihost bằng Ihost.StartAsync để thực hiện một số thử nghiệm tích hợp, và sau khi gọi (và tất nhiên là chờ) Ihost.StopAsync, quá trình vẫn không kết thúc. Chỉ sau khi gọi Ihost.Dispose, quy trình chấm dứt. Cảm ơn bạn vì tiền boa
Malte R

6

Điều này không giải thích tại sao nó xảy ra, nhưng tôi sẽ không gọi Environment.Exittrình xử lý sự kiện nút như mẫu của bạn - thay vào đó hãy đóng biểu mẫu chính như được đề xuất trong câu trả lời của rene .

Đối với một AppDomain.UnhandledExceptiontrình xử lý, có lẽ bạn chỉ có thể đặt Environment.ExitCodehơn là gọiEnvironment.Exit .

Tôi không chắc chắn những gì bạn đang cố gắng để đạt được ở đây. Tại sao bạn muốn trả lại mã thoát khỏi ứng dụng Windows Forms? Thông thường mã thoát được sử dụng bởi các ứng dụng giao diện điều khiển.

Tôi đặc biệt quan tâm đến những gì bạn có thể làm để tránh sự cố này Gọi môi trường .Exit () là bắt buộc để ngăn hộp thoại WER hiển thị.

Bạn có thử / bắt trong phương thức Chính không? Đối với các ứng dụng Windows Forms, tôi luôn có một lần thử / bắt xung quanh vòng lặp thông báo cũng như các trình xử lý ngoại lệ chưa được xử lý.


Khá chắc chắn rằng bạn nên gọi Application.Exitthay vì Environment.Exit.
dùng541686

7
Xin lỗi, đây không phải là một cách giải quyết. Yêu cầu gọi môi trường.Exit () để ngăn hộp thoại WER hiển thị. Lưu ý "thực tế đã biết" là tốt, mã thoát không thành vấn đề.
Hans Passant

7
@Hans: đang bắt AppDomain.UnhandledException để cố gắng tránh hộp thoại WER hợp pháp ngay từ đầu? Ý tôi là, nếu có một ngoại lệ chưa được xử lý, hộp thoại WER được cho là hiển thị, phải không?
Harry Johnston

2

Tôi đã tìm thấy vấn đề tương tự trong ứng dụng của mình, chúng tôi đã giải quyết nó với cấu trúc sau:

Environment.ExitCode=1;
Application.Exit();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.