2010-11-10 5 views
7

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

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

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

Спасибо, Alex

UPDATE:

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

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! 

ответ

4

Вы можете использовать это быстро indentify нити вашего процесса:

using System.Diagnostics; 

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads; 

Тогда вы можете use kernel32.dll with 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); 
+0

Выглядит многообещающе, спасибо, я дам ему – AlexC

+0

Не стесняйтесь возвращаться сюда и рассказывать нам, если это сработало. :) – bitbonk

+2

Вам также нужен GetCurrentThreadId(), чтобы вы не приостанавливали себя. Случайный тупик вполне вероятен, ничего не выделяйте. –

0

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

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

+0

Спасибо, хотя для этого мне нужно было бы получить все объекты Thread для этого, для которых я не могу найти перечислитель. (Process.Threads возвращают коллекцию ProcessThreads, а не Threads) – AlexC

1

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

Jon Skeet считает, что you can't enumerate managed threads в нормальном коде C#, хотя он и намекает на возможное решение.

+0

Согласитесь: это действительный прецедент для Suspend. –

+0

Спасибо, хотя для этого мне нужно было бы получить все объекты Thread для этого, для которых я не могу найти перечислитель. (Process.Threads возвращают коллекцию ProcessThreads, а не Threads) – AlexC

1

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

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

+0

Ну, мне нужно приостановить все потоки, кроме Thread.CurrentThread, а затем спать, что для [insert time here], а затем возобновить все потоки. – AlexC

1

От моего pov это звучит не так.

  • Какие тесты вы пишете? Если вы говорите об модульных тестах, то это не тестовый пример устройства - это больше похоже на интеграционный тест.
  • Рассмотрите возможность выделения вызовов API в классе, а затем используйте инъекцию зависимостей, чтобы вы могли протестировать без сторонней библиотеки с mocks/stubs и также может спровоцировать/протестировать исключение, поднятое из сторонней библиотеки
+0

Хорошо сказано. Но, вероятно, уже слишком поздно. – bitbonk

+0

Это не был единичный тест или интеграционный тест. Я просто хотел, чтобы небольшое приложение проверило, что проблема была вызвана вводом отладчика (и что это не вызвано программным обеспечением, которое я разрабатываю). Сторонняя библиотека обернута в пользовательский API, как вы предложили (и я использую DI в своих модульных тестах приложений по той причине, что вы предлагаете), но исключение не было получено из сторонней библиотеки, и ошибка не была воспроизведена путем создания некоторые API-вызовы в определенном порядке, так сложно понять, как здесь может помочь инъекция зависимостей? – AlexC