Solved

_endthread in DLL Process Detach

Posted on 1997-10-30
14
947 Views
Last Modified: 2013-12-03
I have a  NT 32 bit DLL that creates a helper thread in the PROCESS_ATTACH using _beginthread().  When I load the DLL through a VB app, everything works fine until I end the app.  That's when I get an ACCVIO out of VB.  I think the problem is that I try to end the thread out of the PROCESS_DETACH.  I set an event, which I WaitOnSingleObject() for in the ThreadProc.  I think that the problem has something to do with NT wanting to serialize thread activity with the DLLMain callls in my DLL.

Anyway, my question is:
How can I end this thread without ACCVIO'ing given that  I don't know to end the thread until I get the PROCESS_DETACH.
0
Comment
Question by:rcc
  • 6
  • 6
  • 2
14 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 1408080
In Win 32 (NT or 95) only one thread can be attaching (or detaching to a DLL) at a time.  If you create a new thread during attachment the new thread wont't run until the first thread is done attaching because the new thread needs to attach to.  If the first thread waits for the new thread to run before finishing attaching and the new thread waits for the first to finish attacking before it runs, you're going to have a long wait.

Opps, I didn't read your question quite clearly enough, but the same problem occurs durring termination.  The first thread waits and doesn't terminate until a different thread terminates, but that thread doesn't terminate because the first one is waiting in the detach process.

As for a solution, I'd need more information about the nature of what you are doing.  For example, why does the first thread need to wait after it terminates the other?
0
 
LVL 2

Expert Comment

by:anichini
ID: 1408081
Try calling DiableThreadLibraryCalls for your DLL before setting the event to kill the second thread. This will cause the second thread to NOT try and call your DLLMAIN with a THREAD_DETACH message.


0
 

Author Comment

by:rcc
ID: 1408082
There is no reason why the 2nd thread should wait.  I would just like it to end.  If I return from the ThreadProc(), I get an ACCVIO with a call stack like this:

RtlpWaitForCriticalSection@4 + 149 bytes
RtlEnterCriticalSection@4 + 67 bytes
_lock(int 0x00000009) line 247
_nh_malloc_dbg(unsigned int 0x00000074, int 0x00000000, int 0x00000002, char * 0x1024bc54, int 0x000000e7) line 238 + 7 bytes
_malloc_dbg(unsigned int 0x00000074, int 0x00000002, char * 0x1024bc54, int 0x000000e7) line 163 + 27 bytes
_calloc_dbg(unsigned int 0x00000001, unsigned int 0x00000074, int 0x00000002, char * 0x1024bc54, int 0x000000e7) line 493 + 21 bytes
_getptd() line 232 + 21 bytes
_endthread() line 220 + 5 bytes
_threadstart(void * 0x02b40c10) line 176
BaseThreadStart@8 + 81 bytes

I'm not sure what is wrong.  Which critical section is it waiting for? and Why the ACCVIO?  Like I said, I SetEvent in the PROCESS_DETACH, which triggers the ThreadProc to return.  This ought to cause my thread to exit gracefully, but it doesn't.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1408083
It might be helpful to see some code if you can cut out the unimportant parts.
0
 
LVL 2

Accepted Solution

by:
anichini earned 100 total points
ID: 1408084
The critical section it is waiting for is in the standard runtime library. Microsoft uses critical sections to synchronize access to various parts of the runtime library in the multithreaded version.

Perhaps the runtime library has already been freed up at the point the second thread gets to this call (perhaps it was freed as a result of the PROCESS_DETACH). Actually, I could see a situation where the first thread has the PROCESS_DETACH called, and you call SetEvent(). Before the second thread exits, the first thread continues to run, returning from your DllMain into the runtime library's DLL main, which in response to the process detach message probably frees up its resources. Then you switch to the second thread, which because of the set event goes on its merry wait to _endthread(), but because the runtime library's state was freed, it gets an access violation.

A possible solution would be to have the first thread wait for the second thread to die. A way to do this is to do a WaitForSingleObject on the thread's handle.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1408085
The answer sounds reasonable, but I would think that the multi-thread version of the run-time libraries would not allow this kind of problem to occur.  That is, when the 1st thread terminates it should release resources for that thread only, not for all threads.  (In this respect it should not treat the primary (original) thread differently that the secondary threads.)  Are you linking to the multi-threaded library?
0
 

Author Comment

by:rcc
ID: 1408086
Yes, I'm linking to the multi-thread library.

There is one problem with your solution.  Since this DLL is attached to an OCX which could be loaded in VB, I don't really know when the program is ending.  In other words, the PROCESS_DETACH is my indication that thread #1 is ending; I can't call WaitForSingleObject(hthread) in the PROCESS_DETACH.  I can call TerminateThread, but the NT docs are a little unclear of any problems that I might cause; it says that the thread won't clean up it's stack.  I ran some test code, and it appears that memory does get cleaned up, but is that true?  Is TerminateThread safe?
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 22

Expert Comment

by:nietod
ID: 1408087
To the best of my knowledge TerminateThread should be avoided.

  It does not allow the thread to clean up in many ways.  Resources used by the thread, like open files, memory used by the operating system, memory used by the run-time library, etc. may not be freed.  These resources will usually be freed when the entire process terminates, but not always.  For example if a library creates a GDI object (a brush say) when it attaches.  The brush will never be freed if you use TerminateThread.
0
 
LVL 2

Expert Comment

by:anichini
ID: 1408088
I guess I wasn't clear on what I meant. Here's what I meant:

// global
HANDLE g_hEvent;
HANDLE g_hThread2; // handle to second thread

// inside your dll main
{
// ...
case PROCESS_DETACH:
// assume g_hEvent was created earlier
SetEvent(g_hEvent); // tell thread2 to die
WaitForSingleObject(g_hThread2); // wait for thread2 to die
break; // break out of dll main
// ...
}

// your second thread2 should periodically check the status of g_hEvent or (preferably) use one of th WaitForXXX functions. When g_hEvent is signaled your second thread should exit.


0
 
LVL 22

Expert Comment

by:nietod
ID: 1408089
Nope!  This should cause a deadlock.

Inside the detach code you do this:

SetEvent(g_hEvent); // tell thread2 to die
WaitForSingleObject(g_hThread2); // wait for thread2 to die

But thread2 cannot die until thread 1 returns from the detach notification.  Why?  because only one thread can be in the attach/detach notification at a time.  Thread 1 will wait for thread 2 finish terminating before it leaves the detack notification, but thread 2 won't even start to terminate until thread 1 leaves the detach notification code.  That is a deadlock.
0
 
LVL 2

Expert Comment

by:anichini
ID: 1408090
it won't deadlock if you call DiableThreadLibraryCalls. The deadlock occurs with the synchronization that Win32 puts around DllMain, but if the second thread never calls DllMain there will be no deadlock.


0
 
LVL 22

Expert Comment

by:nietod
ID: 1408091
DisableThreadLibraryCalls().  Hadn't seen that before.  That should prevent the deadlock, if it is safe to use.  Some librarys will require thread detach notification.  


0
 
LVL 2

Expert Comment

by:anichini
ID: 1408092
But DisableThreadLibraryCalls() has you specify which DLL you want to disable calls on, so he can just disable it for his DLL.

0
 
LVL 2

Expert Comment

by:anichini
ID: 1408093
Wait a second - I found a better answer in a back issue of MSJ.

The solution is too lengthy for me to post here, but if rcc doesn't have access to MSDN (which has this back issue), I can post the code.

The person asking the question has a problem similar to yours, although they were using ISAPI. The solution is to not kill the threads off in your DLL_PROCESS_DETACH message. What you do is increment your DLL's reference count in your DLL_PROCESS_ATTACH. This causes your DLL not to be unloaded when VB calls FreeLibrary via OLE, and thus it doesn't get the DLL_PROCESS_DETACH. When the worker thread exits, you call FreeLibraryAndExitThread (in rcc's case, he'll want to call FreeLibrary() on his own DLL and then call _endthread()).

But you must be asking: when does the worker thread terminate? The answer is a small stub DLL you create which forwards all the exports from your real DLL. The stub DLL's only purpose is to call an exported function from your real DLL called ShutdownDLL, which signals the threads telling them to exit.

For the source code and a better explanation, look at MSJ Volume 11, September 1996 "Win32 Q&A", look at the second question.


0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
display png images in VB6 4 373
Vb.Net Loading Word 11 98
SQL to ElasticSearch Query 1 577
How do ASP.NET and MVC work together? 4 25
This tutorial is about how to put some of your C++ program's functionality into a standard DLL, and how to make working with the EXE and the DLL simple and seamless.   We'll be using Microsoft Visual Studio 2008 and we will cut out the noise; that i…
In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This is a video describing the growing solar energy use in Utah. This is a topic that greatly interests me and so I decided to produce a video about it.

919 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now