4
votes

I have a native C++ application running under VS2014 SP2 that uses a lot of multi-threading using my own thread pool class. Typically, the application will have > 32 threads running at any one time, most of which will be idle much of the time. Is there any way in the debugger of seeing which threads in the the thread view are idling (i.e. in a sleep function), as presently, if I break execution the debugger typically brings me back to the sleeping part of an inactive thread;

UINT    _cdecl MyThreadFunc(LPVOID pParam)
{
    CMyThreadSlot *pThreadInfo = (CMyThreadSlot*)pParam;
    while (pThreadInfo->m_pManager->m_Active)
    {
        try
        {
            if (pThreadInfo->m_pActivity)
            {
                pThreadInfo->m_pActivity->Execute();
                pThreadInfo->m_pActivity = NULL;
            }
            else
                Sleep(50);  <-- breaking execution ends up here
        }
        catch (CUserException* e)
        {
            e->Delete();
            if (pThreadInfo->m_pActivity)
                if (pThreadInfo->m_pActivity->m_pThreadGroup)
                    pThreadInfo->m_pActivity->m_pThreadGroup->m_ExceptionThrown = TRUE;
        }
    }
    return CMyThreadManager::ExitOk;
}

If I end up here after breaking, I currently have to trawl through the call stack for each thread to see what was actually executing which can be painful. Even if I break into other code, I'd still also like to know which other threads aren't sleeping and check what they are doing.

Edit: Ok, clunky enough solution, but firing up Process Explorer, right clicking on my running application, selecting properties threads allows me to sort threads by CPU usage, using the Thread ID of active threads then lets me find figure out which threads in use. Main flaw is that this has to be done prior to breaking the running app.

1
Nothing to do with your issue, but I'm wondering why are you using catch (CUserException* e) instead of just catch (CUserException const & e). What advantages does pointer bring to your case? - Nawaz
@Nawaz, no reason other than being a sad old MFC hack from the dinosaur era ;) - SmacL
If you use unique name for the threads entry points, then that could be the beginning of your debugging in the right direction. But then it seems very awkward to write different entry points if all of them are going to do the same. One solution could be make the entry point as template. I've used this technique in the past to generate different name for each thread entry point. - Nawaz
Yes. That makes sense. Just try to make your function a function template and instantiate it with different template argument so that you get different name (though compiler-generated one) for each thread. You can even use dummy structs (or integral values) to instantiate it. - Nawaz
Would Concurrency Visualizer help you? visualstudiogallery.msdn.microsoft.com/… Especially the Thread View part: msdn.microsoft.com/en-us/library/dd627193.aspx - A.Fagrell

1 Answers

3
votes

Figured it out. Trick was to initialise threads with below normal priority, set them to normal when running, and reset to below normal afterwards. In thread view on the debugger, sorting by priority then gives you your active threads. So from previous code, thread is initialised as

    CWinThread *pWinThread = AfxBeginThread(MyThreadFunc, MyThreadSlotObject, THREAD_PRIORITY_BELOW_NORMAL);
    MyThreadSlotObject->m_hThread = pWinThread->m_hThread;

and previous code amended as follows;

        if (pThreadInfo->m_pActivity)
        {
            SetThreadPriority(pThreadInfo->m_hThread, THREAD_PRIORITY_NORMAL);
            pThreadInfo->m_pActivity->Execute();
            SetThreadPriority(pThreadInfo->m_hThread, THREAD_PRIORITY_BELOW_NORMAL);
            pThreadInfo->m_pActivity = NULL;
        }

Edit: If you didn't want to change priority, it looks like you could also do it through thread naming handily enough.