Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. TerminateThread hangs

TerminateThread hangs

Scheduled Pinned Locked Moved C / C++ / MFC
question
11 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    maciu2020
    wrote on last edited by
    #1

    Recently, after rewriting a part of my code for multithreading, I noticed that after return from main(), the program doesn't quit. So I added ExitProcess() there. Doesn't work. TerminateThread(). Doesn't work. Doesn't return control. Then I tried to manually kill all the threads I started ( it wasn't necessary before, they should never hang ). Also doesn't return. Furthermore, the process cannot be killed in any way. Advanced Process Terminator can't do it. Any clue?

    M 1 Reply Last reply
    0
    • M maciu2020

      Recently, after rewriting a part of my code for multithreading, I noticed that after return from main(), the program doesn't quit. So I added ExitProcess() there. Doesn't work. TerminateThread(). Doesn't work. Doesn't return control. Then I tried to manually kill all the threads I started ( it wasn't necessary before, they should never hang ). Also doesn't return. Furthermore, the process cannot be killed in any way. Advanced Process Terminator can't do it. Any clue?

      M Offline
      M Offline
      Mark Salsbery
      wrote on last edited by
      #2

      If you break in the debugger when it's hanging, where is the instruction pointer and how many threads are still active at that point? Mark

      Mark Salsbery Microsoft MVP - Visual C++ :java:

      M 1 Reply Last reply
      0
      • M Mark Salsbery

        If you break in the debugger when it's hanging, where is the instruction pointer and how many threads are still active at that point? Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        M Offline
        M Offline
        maciu2020
        wrote on last edited by
        #3

        Unable to attach a debugger. -- modified at 3:18 Saturday 24th November, 2007 Checked the currently running ones with Process Explorer. 19-139 threads. The newer instance-the more threads. How many did I create in total? One for each open file handle, system-wide. I noticed that each running copy of my program leaves some handles unclosed...and number of them is close to the number of threads left...(didn't count precisely, every 5-6 versions I have to restart computer, then I have a problem with resource allocation. And windows (XP SP2 BTW) also has some problems with killing them - closing system is ridiculously slow).

        M 1 Reply Last reply
        0
        • M maciu2020

          Unable to attach a debugger. -- modified at 3:18 Saturday 24th November, 2007 Checked the currently running ones with Process Explorer. 19-139 threads. The newer instance-the more threads. How many did I create in total? One for each open file handle, system-wide. I noticed that each running copy of my program leaves some handles unclosed...and number of them is close to the number of threads left...(didn't count precisely, every 5-6 versions I have to restart computer, then I have a problem with resource allocation. And windows (XP SP2 BTW) also has some problems with killing them - closing system is ridiculously slow).

          M Offline
          M Offline
          Mark Salsbery
          wrote on last edited by
          #4

          maciu2020 wrote:

          Unable to attach a debugger

          hmm...why? It really sounds like you have active threads left running. Closing a thread handle does not eliminate the thread. All threads should terminate themselves by returning. Some thread, usually the "main" thread, should wait for all the threads to terminate. If you're resorting to TerminateThread() and other abnormal ways of stopping a thread, chances are you've got a bad design.  You shouldn't ever need to terminate a thread or process forcefully. Also, make sure you use the proper thread creation functions, depending on what the thread uses:    straight Win32 APIs, use CreateThread()    C runtime (CRT), which includes using new/delete, use _beginthread[ex]()    MFC (which uses all of the above), use AfxBeginThread() Mark

          Mark Salsbery Microsoft MVP - Visual C++ :java:

          M 1 Reply Last reply
          0
          • M Mark Salsbery

            maciu2020 wrote:

            Unable to attach a debugger

            hmm...why? It really sounds like you have active threads left running. Closing a thread handle does not eliminate the thread. All threads should terminate themselves by returning. Some thread, usually the "main" thread, should wait for all the threads to terminate. If you're resorting to TerminateThread() and other abnormal ways of stopping a thread, chances are you've got a bad design.  You shouldn't ever need to terminate a thread or process forcefully. Also, make sure you use the proper thread creation functions, depending on what the thread uses:    straight Win32 APIs, use CreateThread()    C runtime (CRT), which includes using new/delete, use _beginthread[ex]()    MFC (which uses all of the above), use AfxBeginThread() Mark

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            M Offline
            M Offline
            maciu2020
            wrote on last edited by
            #5

            Mark Salsbery wrote:

            maciu2020 wrote: Unable to attach a debugger hmm...why?

            This is what OllyDbg tells me..

            Mark Salsbery wrote:

            It really sounds like you have active threads left running. Closing a thread handle does not eliminate the thread. All threads should terminate themselves by returning.

            Sure. All threads should do it as they have no loops or infinite waits. And when I run one at the time, they all return.

            Mark Salsbery wrote:

            You shouldn't ever need to terminate a thread or process forcefully.

            Yep. And I didn't do it until this strange case.

            Mark Salsbery wrote:

            Also, make sure you use the proper thread creation functions, depending on what the thread uses:

            I use the correct one. I thing it would be good to post the code. It's a slightly modified part of Zoltan Csizmadia's SystemInfo library. My ThreadProc just calls GetFileName() as below. For readability, I stripped security checks and cleanup. BOOL SystemHandleInformation::GetFileName( HANDLE h, CString& str, DWORD processId ) throw() { ULONG size = 0x8000; UCHAR* lpBuffer = NULL; BOOL ret = FALSE; HANDLE handle; HANDLE hRemoteProcess; BOOL remote = processId != GetCurrentProcessId(); DWORD dwId = 0; HANDLE hHeap; if ( remote ) { hRemoteProcess = ::OpenProcess( PROCESS_DUP_HANDLE, TRUE, processId ); handle = DuplicateHandle( hRemoteProcess, h ); } else handle = h; // let's be happy, handle is in our process space, so query the infos :) ret = GetFileNameHelper( handle, str ); INtDll::NtQueryObject ( handle, 1, NULL, 0, &size ); lpBuffer = (UCHAR*)HeapAlloc(hHeap = GetProcessHeap(), 0, sizeof(UCHAR)*size); if ( INtDll::NtQueryObject( handle, 1, lpBuffer, size, NULL ) == 0 ) { SystemInfoUtils::Unicode2CString( (UNICODE_STRING*)lpBuffer, str ); ret = TRUE; } return ret; } #define FILE_NAME_INFORMATION 9 //File related functions void __cdecl SystemHandleInformation::GetFileNameThread( PVOID pParam ) throw() { // This thread function for getting the filename // if access denied, we hang up in this function, // so if it times out we just kill this thread GetFileNameThreadParam* p = (GetFileNameThreadParam*)pParam; UCHAR *lpBuffer = (UCHAR*) VirtualAlloc( NULL, 0x1000*sizeof(U

            M 1 Reply Last reply
            0
            • M maciu2020

              Mark Salsbery wrote:

              maciu2020 wrote: Unable to attach a debugger hmm...why?

              This is what OllyDbg tells me..

              Mark Salsbery wrote:

              It really sounds like you have active threads left running. Closing a thread handle does not eliminate the thread. All threads should terminate themselves by returning.

              Sure. All threads should do it as they have no loops or infinite waits. And when I run one at the time, they all return.

              Mark Salsbery wrote:

              You shouldn't ever need to terminate a thread or process forcefully.

              Yep. And I didn't do it until this strange case.

              Mark Salsbery wrote:

              Also, make sure you use the proper thread creation functions, depending on what the thread uses:

              I use the correct one. I thing it would be good to post the code. It's a slightly modified part of Zoltan Csizmadia's SystemInfo library. My ThreadProc just calls GetFileName() as below. For readability, I stripped security checks and cleanup. BOOL SystemHandleInformation::GetFileName( HANDLE h, CString& str, DWORD processId ) throw() { ULONG size = 0x8000; UCHAR* lpBuffer = NULL; BOOL ret = FALSE; HANDLE handle; HANDLE hRemoteProcess; BOOL remote = processId != GetCurrentProcessId(); DWORD dwId = 0; HANDLE hHeap; if ( remote ) { hRemoteProcess = ::OpenProcess( PROCESS_DUP_HANDLE, TRUE, processId ); handle = DuplicateHandle( hRemoteProcess, h ); } else handle = h; // let's be happy, handle is in our process space, so query the infos :) ret = GetFileNameHelper( handle, str ); INtDll::NtQueryObject ( handle, 1, NULL, 0, &size ); lpBuffer = (UCHAR*)HeapAlloc(hHeap = GetProcessHeap(), 0, sizeof(UCHAR)*size); if ( INtDll::NtQueryObject( handle, 1, lpBuffer, size, NULL ) == 0 ) { SystemInfoUtils::Unicode2CString( (UNICODE_STRING*)lpBuffer, str ); ret = TRUE; } return ret; } #define FILE_NAME_INFORMATION 9 //File related functions void __cdecl SystemHandleInformation::GetFileNameThread( PVOID pParam ) throw() { // This thread function for getting the filename // if access denied, we hang up in this function, // so if it times out we just kill this thread GetFileNameThreadParam* p = (GetFileNameThreadParam*)pParam; UCHAR *lpBuffer = (UCHAR*) VirtualAlloc( NULL, 0x1000*sizeof(U

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #6

              maciu2020 wrote:

              Sure. All threads should do it as they have no loops or infinite waits. And when I run one at the time, they all return.

              "Should"??  No, they MUST.  Your process cannot exit until they do.

              maciu2020 wrote:

              // Wait for finishing the thread if ( WaitForSingleObject( hThread, 80 ) == WAIT_TIMEOUT ) { // Access denied // Terminate the thread TerminateThread( hThread, 0 );

              Why did you pick 80ms to wait here?  What if it takes 81ms? I'm not sure what to say here, there's just no thread synchronization that I see. If you have a function that never returns under certain conditions, and this is the only solution, then all I can think of is trying _endthread() instead of TerminateThread(). Note that even if it works, this is still a kludge - You have no idea what state the system is left in. Mark

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              M 1 Reply Last reply
              0
              • M Mark Salsbery

                maciu2020 wrote:

                Sure. All threads should do it as they have no loops or infinite waits. And when I run one at the time, they all return.

                "Should"??  No, they MUST.  Your process cannot exit until they do.

                maciu2020 wrote:

                // Wait for finishing the thread if ( WaitForSingleObject( hThread, 80 ) == WAIT_TIMEOUT ) { // Access denied // Terminate the thread TerminateThread( hThread, 0 );

                Why did you pick 80ms to wait here?  What if it takes 81ms? I'm not sure what to say here, there's just no thread synchronization that I see. If you have a function that never returns under certain conditions, and this is the only solution, then all I can think of is trying _endthread() instead of TerminateThread(). Note that even if it works, this is still a kludge - You have no idea what state the system is left in. Mark

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                M Offline
                M Offline
                maciu2020
                wrote on last edited by
                #7

                Mark Salsbery wrote:

                Why did you pick 80ms to wait here? What if it takes 81ms?

                Under normal conditions, it shouldn't take even 3ms on a fairly modern machine. Why is it implemented this way? Because with insufficient access rights, NtQueryInformationFile doesn't return...at least not in reasonable time (I didn't write this code, but WAIT_TIMEOUT happens here up to 77 times on my machine. Also with 100 ms which was the default set several years ago by the author of this part). _endthread() would need to be called by the thread itself, which is impossible when NtQueryInformationFile doesn't return. Yes, this can cause a resource leak, I need to rewrite it to use CreateThread instead. Anyway, it's not the case. After a few hours of restarting my computer, I found where is the problem. INtDll::NtQueryObject ( handle, 1, NULL, 0, &size ); // let's try to use the default if ( size == 0 ) size = 0x8000; lpBuffer = (UCHAR*)HeapAlloc(hHeap = GetProcessHeap(), 0, sizeof(UCHAR)*size); if ( INtDll::NtQueryObject( handle, 1, lpBuffer, size, NULL ) == 0 ) { SystemInfoUtils::Unicode2CString( (UNICODE_STRING*)lpBuffer, str ); ret = TRUE; } Neither MSDN nor ntinternals.net write about thread security issues in NtQueryObject. I'm going to try to put it in a critical section and see what happens. Need another restart though :sigh: -- modified at 15:13 Saturday 24th November, 2007 When there's a hung process in memory, it becomes totally unpredictable. X| Even the single treaded, well tested version can hang here. I'm leaving it for today, I'm too tired.

                M 1 Reply Last reply
                0
                • M maciu2020

                  Mark Salsbery wrote:

                  Why did you pick 80ms to wait here? What if it takes 81ms?

                  Under normal conditions, it shouldn't take even 3ms on a fairly modern machine. Why is it implemented this way? Because with insufficient access rights, NtQueryInformationFile doesn't return...at least not in reasonable time (I didn't write this code, but WAIT_TIMEOUT happens here up to 77 times on my machine. Also with 100 ms which was the default set several years ago by the author of this part). _endthread() would need to be called by the thread itself, which is impossible when NtQueryInformationFile doesn't return. Yes, this can cause a resource leak, I need to rewrite it to use CreateThread instead. Anyway, it's not the case. After a few hours of restarting my computer, I found where is the problem. INtDll::NtQueryObject ( handle, 1, NULL, 0, &size ); // let's try to use the default if ( size == 0 ) size = 0x8000; lpBuffer = (UCHAR*)HeapAlloc(hHeap = GetProcessHeap(), 0, sizeof(UCHAR)*size); if ( INtDll::NtQueryObject( handle, 1, lpBuffer, size, NULL ) == 0 ) { SystemInfoUtils::Unicode2CString( (UNICODE_STRING*)lpBuffer, str ); ret = TRUE; } Neither MSDN nor ntinternals.net write about thread security issues in NtQueryObject. I'm going to try to put it in a critical section and see what happens. Need another restart though :sigh: -- modified at 15:13 Saturday 24th November, 2007 When there's a hung process in memory, it becomes totally unpredictable. X| Even the single treaded, well tested version can hang here. I'm leaving it for today, I'm too tired.

                  M Offline
                  M Offline
                  Mark Salsbery
                  wrote on last edited by
                  #8

                  maciu2020 wrote:

                  _endthread() would need to be called by the thread itself

                  Oops, yeah, sorry about that :doh:

                  maciu2020 wrote:

                  Because with insufficient access rights, NtQueryInformationFile doesn't return

                  That's a bummer, as you well know :)  Isn't there a way to do what you're trying to do using documented/supported APIs? Mark

                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                  M 1 Reply Last reply
                  0
                  • M Mark Salsbery

                    maciu2020 wrote:

                    _endthread() would need to be called by the thread itself

                    Oops, yeah, sorry about that :doh:

                    maciu2020 wrote:

                    Because with insufficient access rights, NtQueryInformationFile doesn't return

                    That's a bummer, as you well know :)  Isn't there a way to do what you're trying to do using documented/supported APIs? Mark

                    Mark Salsbery Microsoft MVP - Visual C++ :java:

                    M Offline
                    M Offline
                    maciu2020
                    wrote on last edited by
                    #9

                    Mark Salsbery wrote:

                    Isn't there a way to do what you're trying to do using documented/supported APIs?

                    Unfortunately, there isn't. What I'm doing is making Zoltan Csizmadia's ForceDel (a tool that deletes locked files) more usable. Improved performance (originally-very poor, especially when trying to delete multiple files), GUI, some more features. AFAIK there are 2 ways of doing it. The first is what Zoltan does - enumerating all handles and closing the right ones with CreateRemoteThread(CloseHandle). No documented API gives these handles... There's one more method, implemented in Unlocker. It's not open source and I had no time to reverse it..but it's a kernel mode hack. I guess, a kind of hook...and I think it's even worse than what I'm working at. It works faster though and maybe I'll decide to try to do the same.

                    M 1 Reply Last reply
                    0
                    • M maciu2020

                      Mark Salsbery wrote:

                      Isn't there a way to do what you're trying to do using documented/supported APIs?

                      Unfortunately, there isn't. What I'm doing is making Zoltan Csizmadia's ForceDel (a tool that deletes locked files) more usable. Improved performance (originally-very poor, especially when trying to delete multiple files), GUI, some more features. AFAIK there are 2 ways of doing it. The first is what Zoltan does - enumerating all handles and closing the right ones with CreateRemoteThread(CloseHandle). No documented API gives these handles... There's one more method, implemented in Unlocker. It's not open source and I had no time to reverse it..but it's a kernel mode hack. I guess, a kind of hook...and I think it's even worse than what I'm working at. It works faster though and maybe I'll decide to try to do the same.

                      M Offline
                      M Offline
                      Mark Salsbery
                      wrote on last edited by
                      #10

                      Cool :) I've never played around with that stuff before. Good luck! Mark

                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                      M 1 Reply Last reply
                      0
                      • M Mark Salsbery

                        Cool :) I've never played around with that stuff before. Good luck! Mark

                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                        M Offline
                        M Offline
                        maciu2020
                        wrote on last edited by
                        #11

                        Thanks that you tried to help.

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups