请问用C++编写的大型程序,怎样测试和检测线程死锁?
提供好的测试工具和测试思路都行!

解决方案 »

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