高分相赠--如何测试线程死锁?

时间:2021-02-09 19:46:40
请问用C++编写的大型程序,怎样测试和检测线程死锁?
提供好的测试工具和测试思路都行!

5 个解决方案

#1


用CEvent或是CCriticalSection类来加个临界区

#2


在程序运行当中,用windows的任务管理器查看进程,如果未占用cpu时间且有多个线程,则形成了死锁

#3


when you create a thread, output its threadid, function of the thread
at runtime,枚举进程中所有线程,看他们的cpu时间
    hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID); 
    if (hThreadSnap == INVALID_HANDLE_VALUE) 
        return FALSE; 

    // Fill in the size of the structure before using it. 

    tie.te32.dwSize = sizeof(THREADENTRY32); 

    // Walk the thread snapshot to find all threads of the process. 
    // If the thread belongs to the process, add its information 
    // to the display list.

    if (Thread32First(hThreadSnap, &tie.te32)) 
    { 
        do 
        { 
//
// if the thread belongs to the given process...
//
            if (tie.te32.th32OwnerProcessID == dwProcessID) 
            { 
if(bGetContext && (dwThisThread != tie.te32.th32ThreadID))
{
//
// get some more information about this thread
//
HANDLE hThread = ::OpenThread(THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION, FALSE, tie.te32.th32ThreadID);
if(hThread != INVALID_HANDLE_VALUE)
{
::SuspendThread(hThread); // otherwise we dont get the context
{
tie.ctx.ContextFlags = CONTEXT_FULL;
::GetThreadContext(hThread, &tie.ctx);
}
::ResumeThread(hThread);
::CloseHandle(hThread);
}
}
#ifdef _VERBOSE_DEBUG
TRACE( "\nTID\t\t%d (@%i)\n", tie.te32.th32ThreadID, tie.te32.th32OwnerProcessID);
TRACE( "Base Priority\t%d\n", tie.te32.tpBasePri); 
if(tie.ctx.ContextFlags)
{
TRACE("EIP\t\t0x%08x\n", tie.ctx.Eip);
TRACE("ESP\t\t0x%08x\n", tie.ctx.Esp);
}
#endif

/*
#if defined(USE_STL)
push_back(tie);
#else
Add(tie);
#endif
*/
HANDLE hthread=OpenThread(THREAD_QUERY_INFORMATION,FALSE, tie.te32.th32ThreadID);
if(hthread)
{
ReportThreadTime(hthread,tie.te32.th32ThreadID,false,"");
CloseHandle(hthread);
}
else
{
}
ZeroMemory(&tie, sizeof(THREAD_INFORMATION_EX));
tie.te32.dwSize = sizeof(THREADENTRY32);
            } 
        } 
        while (Thread32Next(hThreadSnap, &tie.te32)); 
        bRet = TRUE; 
    } 
    else 
        bRet = FALSE;          // could not walk the list of threads 

    // Do not forget to clean up the snapshot object. 

    CloseHandle (hThreadSnap); 

#4


void ThreadClass::ReportThreadTime(HANDLE hthread,DWORD threadid, bool log, LPCTSTR threadname)
{
FILETIME createtime;
FILETIME exittime;
FILETIME kernaltime;
FILETIME usertime;
BOOL ret=GetThreadTimes(hthread,&createtime,&exittime,&kernaltime,&usertime);
if(ret==0)
{
//error
LPVOID lpMsgBuf;
FormatMessage( 
FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM | 
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL 
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
//MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
g_Log.Debug("%s:%d GetThreadTimes error:%s",__FILE__,__LINE__,(char*)lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
return;
}
SYSTEMTIME stkernal;
SYSTEMTIME stuser;
FileTimeToSystemTime(&kernaltime,&stkernal);
FileTimeToSystemTime(&usertime,&stuser);
std::ostringstream oss;
oss<<"ThreadClass("<<threadid<<","<<threadname<<") profile(d:h:m:s:ms), user time "<<stuser.wDay<<":"
<<stuser.wHour<<":"<<stuser.wMinute<<":"<<stuser.wSecond<<":"<<stuser.wMilliseconds;
oss<<"; kernal time "<<stkernal.wDay<<":"<<stkernal.wHour<<":"<<stkernal.wMinute<<":"
<<stkernal.wSecond<<":"<<stkernal.wMilliseconds;
}

#5


还有就是提供接口能够随时察看程序中的资源情况,队列大小

#1


用CEvent或是CCriticalSection类来加个临界区

#2


在程序运行当中,用windows的任务管理器查看进程,如果未占用cpu时间且有多个线程,则形成了死锁

#3


when you create a thread, output its threadid, function of the thread
at runtime,枚举进程中所有线程,看他们的cpu时间
    hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID); 
    if (hThreadSnap == INVALID_HANDLE_VALUE) 
        return FALSE; 

    // Fill in the size of the structure before using it. 

    tie.te32.dwSize = sizeof(THREADENTRY32); 

    // Walk the thread snapshot to find all threads of the process. 
    // If the thread belongs to the process, add its information 
    // to the display list.

    if (Thread32First(hThreadSnap, &tie.te32)) 
    { 
        do 
        { 
//
// if the thread belongs to the given process...
//
            if (tie.te32.th32OwnerProcessID == dwProcessID) 
            { 
if(bGetContext && (dwThisThread != tie.te32.th32ThreadID))
{
//
// get some more information about this thread
//
HANDLE hThread = ::OpenThread(THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION, FALSE, tie.te32.th32ThreadID);
if(hThread != INVALID_HANDLE_VALUE)
{
::SuspendThread(hThread); // otherwise we dont get the context
{
tie.ctx.ContextFlags = CONTEXT_FULL;
::GetThreadContext(hThread, &tie.ctx);
}
::ResumeThread(hThread);
::CloseHandle(hThread);
}
}
#ifdef _VERBOSE_DEBUG
TRACE( "\nTID\t\t%d (@%i)\n", tie.te32.th32ThreadID, tie.te32.th32OwnerProcessID);
TRACE( "Base Priority\t%d\n", tie.te32.tpBasePri); 
if(tie.ctx.ContextFlags)
{
TRACE("EIP\t\t0x%08x\n", tie.ctx.Eip);
TRACE("ESP\t\t0x%08x\n", tie.ctx.Esp);
}
#endif

/*
#if defined(USE_STL)
push_back(tie);
#else
Add(tie);
#endif
*/
HANDLE hthread=OpenThread(THREAD_QUERY_INFORMATION,FALSE, tie.te32.th32ThreadID);
if(hthread)
{
ReportThreadTime(hthread,tie.te32.th32ThreadID,false,"");
CloseHandle(hthread);
}
else
{
}
ZeroMemory(&tie, sizeof(THREAD_INFORMATION_EX));
tie.te32.dwSize = sizeof(THREADENTRY32);
            } 
        } 
        while (Thread32Next(hThreadSnap, &tie.te32)); 
        bRet = TRUE; 
    } 
    else 
        bRet = FALSE;          // could not walk the list of threads 

    // Do not forget to clean up the snapshot object. 

    CloseHandle (hThreadSnap); 

#4


void ThreadClass::ReportThreadTime(HANDLE hthread,DWORD threadid, bool log, LPCTSTR threadname)
{
FILETIME createtime;
FILETIME exittime;
FILETIME kernaltime;
FILETIME usertime;
BOOL ret=GetThreadTimes(hthread,&createtime,&exittime,&kernaltime,&usertime);
if(ret==0)
{
//error
LPVOID lpMsgBuf;
FormatMessage( 
FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM | 
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL 
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
//MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
g_Log.Debug("%s:%d GetThreadTimes error:%s",__FILE__,__LINE__,(char*)lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
return;
}
SYSTEMTIME stkernal;
SYSTEMTIME stuser;
FileTimeToSystemTime(&kernaltime,&stkernal);
FileTimeToSystemTime(&usertime,&stuser);
std::ostringstream oss;
oss<<"ThreadClass("<<threadid<<","<<threadname<<") profile(d:h:m:s:ms), user time "<<stuser.wDay<<":"
<<stuser.wHour<<":"<<stuser.wMinute<<":"<<stuser.wSecond<<":"<<stuser.wMilliseconds;
oss<<"; kernal time "<<stkernal.wDay<<":"<<stkernal.wHour<<":"<<stkernal.wMinute<<":"
<<stkernal.wSecond<<":"<<stkernal.wMilliseconds;
}

#5


还有就是提供接口能够随时察看程序中的资源情况,队列大小