Pausing all threads in current process at run time
Asked Answered
L

5

7

I have a bug in my app that seems to show it's face only when I pause the app in the debugger for a few minutes. I suspect this is due to a third party networking library I am using having a heartbeat thread, which becomes disconnected when it can not ping the server while it's heartbeat thread is paused.

I am trying to write a test case app for this to verify that this is the cause of the bug. To do so, I need a way to pause all the threads in the app (which i will later narrow down to pausing only the thread I suspect may be the heartbeat thread) to simulate pausing the app in the debugger.

Does anyone know how to do this? Is it even possible for one thread to cause another to sleep?

Thanks, Alex

UPDATE:

I ended up deciding that I didn't really need an app to do this for me, seeing as the point was just to verify that pausing in the debugger was causing the disconnect. So, here's what I did... (The simplest ways are often the best... or at least the simplest...)

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

And the output:

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!
Lakh answered 10/11, 2010 at 12:38 Comment(0)
E
4

You can use this to quickly indentify the threads of your process:

using System.Diagnostics;

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads;

Then you can use kernel32.dll with P/Invoke to do whatever you need with those threads. Use OpenThread to get a handle to the desired thread and then suspend it with SuspendThread using that handle.

Here are the P/Invoke declaration for the two methods:

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

[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
Equipotential answered 10/11, 2010 at 12:42 Comment(2)
You also need GetCurrentThreadId() so you don't suspend yourself. Random deadlock is quite likely, don't allocate anything.Taffeta
Ended up using my solution above to verify the bug. This looks like what I was looking for though, so will accept. Thanks.Lakh
S
1

You can suspend threads by calling Thread.Suspend. The documentation gives big "DON'T DO THIS!" deprecation warnings, but I think yours is a valid use case.

Jon Skeet thinks you can't enumerate managed threads in normal C# code, though he does hint at a possible solution.

Sidoney answered 10/11, 2010 at 12:45 Comment(2)
Agree: this is a valid use-case for Suspend.Curator
Thanks, though for this, I would need to get ahold of all the Thread objects to do this, which I can't find an enumerator for. (Process.Threads return a collection of ProcessThreads, not Threads)Lakh
A
1

I assume you're not going to pause all the threads in the application, otherwise there will be nothing running to un-suspend them. Or have I missed something?

A suggestion: Try giving names to all the threads you create. Any threads without a name, or that don't match your naming convention, must have been create by a third-party component. This might get you to the root cause quicker without having to pause lots of threads.

Aprilaprile answered 10/11, 2010 at 12:51 Comment(1)
Well, I need to pause all the threads except Thread.CurrentThread, then sleep that for [insert time here], then resume all the threads.Lakh
E
1

From my pov this sounds not right.

  • Which kind of tests are you writing? If you are speaking about unit tests, then this is not a Unit test case - sounds more like integration test
  • Consider to isolate the API calls in a class and then use dependendcy injection so that you can test without the 3rd party library with mocks/stubs and can also provoke/test an exception raised from the 3rd party library
Elke answered 10/11, 2010 at 13:6 Comment(2)
Well said. But it is probably too late now.Equipotential
This wasn't a unit test or an integration test. I just wanted a little app to verify that the problem was caused by entering the debugger (and that it was not being caused by the software I am developing). The third party library is wrapped in a custom API as you suggested (and I use DI in my apps unit tests for the reason you suggest) but no exception was being raised from the third party library, and the bug wasn't reproducable by making some API calls in a particular order, so hard to see how dependency injection would help here?Lakh
F
0

You could call the Thread.Suspend then Thread.Resume methods but those are deprecated and is not recommneded to use them.

But you can do the following: Have a boolean flag that when set you put your thread on a big sleep. OR Better to use ManualResetEvent.

Frendel answered 10/11, 2010 at 12:43 Comment(1)
Thanks, though for this, I would need to get ahold of all the Thread objects to do this, which I can't find an enumerator for. (Process.Threads return a collection of ProcessThreads, not Threads)Lakh

© 2022 - 2024 — McMap. All rights reserved.