C# приостановка всех потоков

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

// 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 на рассматриваемую машину, если этого можно избежать. Как я могу это сделать?

2 ответов


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

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

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

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

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


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

с документация:

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

поэтому, когда вы будете пытаться просматривать содержание такой еще не обжитый объект, то вам, вероятно, тоже закрыта. Поэтому независимо от того, что вы используете для приостановки других потоков, вы можете оказаться в том же сценарии. Итак, единственная возможность-изменить реализацию других потоков, чтобы иметь возможность задавать им приостановить себя:есть ли способ бесконечно приостановить поток?.