Приостановка всех потоков в текущем процессе во время выполнения - PullRequest
7 голосов
/ 10 ноября 2010

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

Я пытаюсь написать тестовый примерПриложение для этого, чтобы убедиться, что это является причиной ошибки.Для этого мне нужен способ приостановить все потоки в приложении (который я позже сужу до приостановки только потока, который, как я подозреваю, может быть потоком пульса), для имитации приостановки приложения в отладчике.

Кто-нибудь знает как это сделать?Возможно ли, чтобы один поток заставлял другой спать?

Спасибо, Алекс

ОБНОВЛЕНИЕ:

Я решил, что мне действительно не нужно приложение длясделайте это для меня, так как смысл был просто в том, чтобы убедиться, что приостановка в отладчике вызывала отключение.Итак, вот что я сделал ... (Простейшие способы часто самые лучшие ... или, по крайней мере, самые простые ...)

    private static void Main(string[] args)
    {
        IPubSubAdapter adapter = BuildAdapter();
        bool waitingForMessage;
        adapter.Subscribe(_topic, message => waitingForMessage = false, DestinationType.Topic);
        Stopwatch timePaused = new Stopwatch();
        while (adapter.IsConnected)
        {
            Console.WriteLine("Adapter is still connected");
            waitingForMessage = true;
            adapter.Publish(_topic, "testmessage", DestinationType.Topic);
            while (waitingForMessage)
            {
                Thread.Sleep(100);
            }
            timePaused.Reset();
            timePaused.Start();
            Debugger.Break();
            timePaused.Stop();
            Console.WriteLine("Paused for " + timePaused.ElapsedMilliseconds + "ms.");
            Thread.Sleep(5000); // Give it a chance to realise it's disconnected.
        }
        Console.WriteLine("Adapter is disconnected!");
        Console.ReadLine();
    }

И вывод:

Adapter is still connected
Paused for 10725ms.
Adapter is still connected
Paused for 13298ms.
Adapter is still connected
Paused for 32005ms.
Adapter is still connected
Paused for 59268ms.
Adapter is disconnected!

Ответы [ 5 ]

4 голосов
/ 10 ноября 2010

Вы можете использовать это для быстрой идентификации потоков вашего процесса:

using System.Diagnostics;

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads;

Тогда вы можете использовать kernel32.dll с P / Invoke , чтобы делать с этими потоками все, что вам нужно. Используйте OpenThread , чтобы получить дескриптор нужного потока, а затем приостановите его с помощью SuspendThread , используя этот дескриптор.

Вот объявление P / Invoke для двух методов:

[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
1 голос
/ 10 ноября 2010

Из моего POV это звучит не так.

  • Какие тесты вы пишете? Если вы говорите о модульных тестах, то это не тестовый блок - это больше похоже на интеграционный тест
  • Рассмотрите возможность изолировать вызовы API в классе, а затем использовать внедрение зависимостей, чтобы можно было тестировать без сторонней библиотеки с помощью mock / stubs, а также вызывать / тестировать исключение, вызванное сторонней библиотекой
1 голос
/ 10 ноября 2010

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

Совет: попробуйте дать имена всем темам, которые вы создаете.Любые потоки без имени или не соответствующие соглашению об именах должны создаваться сторонним компонентом.Это может быстрее привести вас к первопричине, не останавливая множество потоков.

1 голос
/ 10 ноября 2010

Вы можете приостановить темы, позвонив Thread.Suspend.Документация дает большое "НЕ ДЕЛАЙ ЭТОГО!"предупреждения об устаревании, но я думаю, что это ваш правильный вариант использования.

Джон Скит считает, вы не можете перечислить управляемые потоки в обычном коде C #, хотя он намекает на возможное решение.1006 *

0 голосов
/ 10 ноября 2010

Вы можете вызывать методы Thread.Suspend затем Thread.Resume, но они устарели и не рекомендуется их использовать.

Но вы можете делать следующее: иметь логический флаг, который при установке вы ставитенить на большой сон.ИЛИ Лучше использовать ManualResetEvent .

...