6

Tôi có một vấn đề có thể khá độc đáo. Tôi có một ứng dụng chạy trên một hộp không đầu trong nhiều giờ khi tôi không có mặt, nhưng không quan trọng. Tôi muốn có thể gỡ lỗi ứng dụng này từ xa bằng cách sử dụng Visual Studio. Để làm như vậy, tôi có mã trông như thế này:C# đình chỉ tất cả các chủ đề

// Suspend all other threads to prevent loss 
// of state while we investigate the issue. 
SuspendAllButCurrentThread(); 
var remoteDebuggerProcess = new Process 
    { 
     StartInfo = 
      { 
       UseShellExecute = true, 
       FileName = MsVsMonPath; 
      } 
    }; 
// Exception handling and early return removed here for brevity. 
remoteDebuggerProcess.Start(); 

// Wait for a debugger attach. 
while (!Debugger.IsAttached) 
{ 
    Thread.Sleep(500); 
} 
Debugger.Break(); 

// Once we get here, we've hit continue in the debugger. Restore all of our threads, 
// then get rid of the remote debugging tools. 
ResumeAllButCurrentThread(); 

remoteDebuggerProcess.CloseMainWindow(); 
remoteDebuggerProcess.WaitForExit(); 

Ý tưởng được rằng cách này, tôi nhấn một lỗi trong khi tôi đi, và việc áp dụng có hiệu quả tạm dừng bản thân và chờ đợi một trình gỡ lỗi từ xa đính kèm , sau lần đầu tiên tiếp tục tự động nhận được ngữ cảnh phù hợp nhờ cuộc gọi Debugger.Break.

Đây là vấn đề: Triển khai SuspendAllButCurrentThread hóa ra là không cần thiết. Thread.Suspend không được dùng nữa và tôi không thể P/Gọi xuống SuspendThread vì không có ánh xạ một-một giữa các chuỗi được quản lý và chuỗi gốc (vì tôi cần giữ nguyên luồng hiện tại). Tôi không muốn cài đặt Visual Studio trên máy trong câu hỏi nếu nó có thể có thể tránh được. Làm thế nào tôi có thể thực hiện công việc này?

+0

Câu hỏi ngu ngốc có thể, nhưng không VS cho phép gỡ lỗi từ xa mà không cần phải nhảy qua các vòng này? Tôi luôn giả định rằng bạn có thể gỡ lỗi từ xa mà không cần thay đổi mã, nhưng tôi phải thừa nhận rằng tôi đã từng sửa lỗi cục bộ, – Surfbutler

Trả lời

5

tôi không thể P/Gọi xuống SuspendThread vì không có one-to-one ánh xạ giữa đề quản lý và đề bản địa

Bạn không thể liệt kê chủ đề quản lý, hoặc, chỉ đề không được quản lý. Có thực tế một ánh xạ một-một giữa chúng, chúng chỉ làm cho khó tìm ra nó. Mục đích ban đầu là cho phép tạo một máy chủ CLR tùy chỉnh không sử dụng các luồng hệ điều hành để thực hiện Thread, một yêu cầu của nhóm SQL Server muốn sử dụng các sợi thay thế. Điều đó không bao giờ làm việc, họ không thể làm cho nó đủ đáng tin cậy. Không tồn tại máy chủ CLR thực sự nào không sử dụng các luồng hệ điều hành thực.

Vì vậy, bạn có thể sử dụng Process.GetCurrentProcess() để liệt kê tất cả các chuỗi của bạn. Và tránh đình chỉ của riêng bạn bằng cách ghim GetCurrentThreadId(), so sánh nó với ProcessThread.Id

Làm thế nào đáng tin cậy đó sẽ là một đoán, không cố gắng làm bất cứ điều gì quyết liệt như gửi một cảnh báo để nhắc bạn rằng nó là thời gian để đính kèm trình gỡ rối. Bạn có thể đã đình chỉ một chuỗi đang thực thi mã bên trong Windows và có được khóa toàn cầu.Cũng như một chuỗi công nhân CLR, giống như chuỗi kết thúc hoặc chuỗi GC nền.

Cách tiếp cận tốt hơn là sử dụng quy trình bảo vệ riêng biệt thực hiện tất cả điều này, giống như trình gỡ lỗi. Sử dụng một EventWaitHandle được đặt tên mà bạn tạo trong chương trình bảo vệ và OpenExisting() trong chương trình chính của bạn. Chương trình bảo vệ cần WaitAny() trên bộ điều khiển chờ đợi đó cũng như quy trình. Chương trình chính của bạn bây giờ có thể gọi Set() để đánh thức chương trình bảo vệ. Mà bây giờ có thể an toàn đình chỉ tất cả các chủ đề.

+0

Giả sử rằng tôi tạm ngưng một thứ gì đó bên trong Windows bằng khóa toàn cầu - làm thế nào để một trình gỡ rối tránh được vấn đề này? Thứ hai, trong trường hợp này, tôi sẽ P/Gọi xuống 'SuspendThread' là tốt hơn là sử dụng 'Thread.Suspend' không được chấp nhận, đúng không? – Octavianus

+0

Nó không tránh được. Đó là lý do tại sao trình gỡ lỗi phải luôn là một quá trình riêng biệt. Có, pinvoke nó. –

+0

Được rồi, vậy nghĩa là khóa toàn cầu cụ thể cho quy trình? Cách khác, có cách nào để gỡ rối đăng ký thông báo của một trình gỡ lỗi khác đang cố đính kèm không? – Octavianus

1

Vấn đề chính với Thread.Suspend là nó có thể để lại một số đối tượng trong trạng thái không sử dụng được.

Từ documentation:

Không sử dụng các phương pháp ngưng và tiếp tục để đồng bộ hóa các hoạt động của chủ đề. Bạn không có cách nào để biết mã nào mà một chuỗi đang thực hiện khi bạn tạm ngưng mã đó. Nếu bạn tạm dừng một chuỗi trong khi nó giữ khóa trong khi đánh giá quyền bảo mật, các chủ đề khác trong AppDomain có thể bị chặn. Nếu bạn tạm dừng một chuỗi trong khi đang thực hiện một quy trình một hàm tạo lớp, các chủ đề khác trong AppDomain là cố gắng sử dụng lớp đó sẽ bị chặn. Deadlocks có thể xảy ra rất dễ dàng .

Vì vậy, khi bạn sẽ cố gắng xem nội dung của đối tượng như vậy nhưng không sử dụng được, bạn có thể cũng sẽ bị khóa. Vì vậy, bất kể những gì bạn sử dụng để đình chỉ các chủ đề khác, bạn có thể kết thúc trong cùng một kịch bản. Và như vậy, khả năng duy nhất là sửa đổi việc thực hiện các chủ đề khác để có thể yêu cầu họ đình chỉ bản thân: Is there a way to indefinitely pause a thread?.

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