6

У меня есть проблема, которая может быть довольно уникальной. У меня есть приложение, которое работает в безголовой коробке в течение долгих часов, когда я не присутствую, но не критично. Я хотел бы иметь возможность отлаживать это приложение удаленно с помощью Visual Studio. Для того, чтобы сделать это, у меня есть код, который выглядит следующим образом:C# приостановить все темы

// 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(); 

Идея заключается в том, что этот путь, я ударил ошибку в то время как я далеко, и приложение эффективно приостанавливает себя и ждет удаленный отладчик присоединить , который после первого продолжения автоматически получает правильный контекст благодаря вызову Debugger.Break.

Возникла проблема: Выполнение SuspendAllButCurrentThread оказывается нетривиальным. Thread.Suspend устарел, и я не могу выполнить P/Invoke до SuspendThread, потому что между управляемыми потоками и собственными потоками нет однозначного сопоставления (так как мне нужно сохранить текущий поток в живых). Я не хочу устанавливать Visual Studio на рассматриваемую машину, если ее можно избежать. Как я могу сделать эту работу?

+0

Глупый вопрос, вероятно, но не позволяет VS удаленная отладка без необходимости перепрыгивать через эти обручи? Я всегда предполагал, что вы можете удаленно отлаживать без изменений кода, но я должен признать, что я только когда-либо отлаживал локально, – Surfbutler

ответ

5

Я не могу P/Invoke вниз SuspendThread, потому что нет никакого отображения один-к-одному между управляемыми потоками и собственными потоками

Вы не можете перечислять удалось темы либо только неуправляемые потоки. На самом деле является взаимно однозначным сопоставлением между ними, они просто затрудняли его поиск. Первоначальное намерение состояло в том, чтобы разрешить создание пользовательского хоста CLR, который не использовал потоки операционной системы для реализации Thread, запрос группы SQL Server, который хотел использовать волокна вместо этого. Это никогда не получилось, они не могли получить его достаточно надежным. Нет реального хоста CLR, который не использует реальные потоки операционной системы.

Итак, вы можете использовать Process.GetCurrentProcess(). Темы для перечисления всех ваших потоков. И избежать подвешивания самостоятельно, pinvoking GetCurrentThreadId(), сравнивая его с ProcessThread.Id

Насколько надежны, что это будет догадка, не пытайтесь сделать что-нибудь Резкие как отправка оповещения, чтобы напомнить вам, что пришло время подключить отладчик. Возможно, вы хорошо приостановили поток, который выполнял код внутри Windows и приобрел глобальную блокировку.Как и рабочий поток CLR, например поток финализатора или поток GC GC.

Лучшим подходом является использование отдельного процесса защиты, который делает все это, как и отладчик. Используйте именованную EventWaitHandle, которую вы создаете в защитной программе и OpenExisting() в своей основной программе. Программе охраны необходимо WaitAny() на этом дескрипторе ожидания, а также в процессе. Теперь ваша основная программа может просто вызвать Set(), чтобы разбудить программу охраны. Теперь можно безопасно приостановить все потоки.

+0

Предположим, что я приостановил что-то внутри Windows с помощью глобальной блокировки - как отладчик избегает этой проблемы? Во-вторых, в этом случае я бы P/Invoke спустил 'SuspendThread', а не использовал устаревший« Thread.Suspend », правильно? – Octavianus

+0

Этого не избежать. Именно поэтому отладчик всегда должен быть отдельным процессом. Да, приподнять. –

+0

Итак, вы имеете в виду глобальную блокировку, специфичную для процесса? В качестве альтернативы этому, существует ли способ отладки регистрироваться для уведомления другого отладчика, пытающегося подключиться? – Octavianus

1

Основная проблема с Thread.Suspend заключается в том, что он может оставить какой-либо объект в непригодном для использования состоянии.

От documentation:

Не используйте приостанавливать и возобновлять методы для синхронизации деятельности потоков. У вас нет способа узнать, какой код выполняет нить , когда вы его приостанавливаете. Если вы приостановите поток, пока он имеет блокировки во время оценки разрешения безопасности, другие потоки в AppDomain могут быть заблокированы. Если вы приостановите поток, пока выполняется , выполняющий конструктор класса, другие потоки в AppDomain, которые пытаются использовать этот класс, блокируются. Тупики могут встречаться очень легко .

Поэтому, когда вы попытаетесь просмотреть содержимое такого неиспользуемого объекта, вы, вероятно, тоже заблокируете его. Поэтому, независимо от того, что вы используете для приостановки других потоков, вы можете оказаться в том же сценарии. Итак, единственная возможность - изменить реализацию других потоков, чтобы попросить их приостановить себя: Is there a way to indefinitely pause a thread?.

Смежные вопросы