Re: QueueUserWorkItem with functions in a DLL, how to unload safely?
- From: Stefan Kuhr <kustt110@xxxxxx>
- Date: Sat, 28 Jan 2006 21:26:57 +0100
Hello Skywing,
Skywing wrote:
>
> Well, that's a tricky thing to solve. The easiest way to do it is to wrap
> the call to the DLL-provided work item routine in a function that will
> always remain loaded (such as a function present in the main .exe for the
> process).
>
> For example, you might have the .exe export a QueueUserWorkItem-type
> function to the DLL. This function would call QueueUserWorkItem internally,
> but instead of passing the ThreadProc/Context directly to QueueUserWorkItem,
> it would instead pass the address of a wrapper function and a structure that
> contains the original function to call and the original context.
>
> For example... (assume this code resides in the main .exe image and plugin
> DLLs call into MyQueueUserWorkItem to queue a work item - this code would in
> reality need to track reference counts on a per dll basis and not globally,
> but that's specific to your implementation so I just used a global reference
> count to get the idea across):
You indeed got the idea across, thanks for your answer. I had the almost
same idea in case I cannot find a more elegant solution. Meanwhile I
found a method that looks even a bit more elegant to me. Im case you are
interested, read on:
As part of the initialization, after loading the plugin, the exe passes
to the plugin a function pointer of type
typedef BOOL (__stdcall *MA_QUEUE_USER_WORK_ITEM)(LPTHREAD_START_ROUTINE
fnThreadPoolFunc, LPVOID pContext, ULONG dwFlags, LPLONG plRefCount);
and this points to the function MAQueueUserWorkItem which is implemented
in the exe (and which therefore stays alive during the whole process):
typedef struct tagQUWI_PACKET
{
LPTHREAD_START_ROUTINE m_pfnThreadPoolFunc;
LPVOID m_lpContext;
LPLONG m_plRefCount;
}
QUWI_PACKET, *PQUWI_PACKET;
BOOL __stdcall MAQueueUserWorkItem(LPTHREAD_START_ROUTINE
fnThreadPoolFunc, LPVOID pContext, ULONG dwFlags, LPLONG plRefCount)
{
#ifdef _DEBUG
MA_QUEUE_USER_WORK_ITEM pfn = MAQueueUserWorkItem;
pfn = NULL;
#endif
if(!fnThreadPoolFunc || !plRefCount)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
PQUWI_PACKET pqwip = (PQUWI_PACKET)LocalAlloc(LPTR,
sizeof(QUWI_PACKET));
if(!pqwip)
return FALSE; // use the LocalAlloc last error
pqwip->m_lpContext = pContext;
pqwip->m_plRefCount = plRefCount;
pqwip->m_pfnThreadPoolFunc = fnThreadPoolFunc;
if (QueueUserWorkItem(SafeThreadProc, pqwip, dwFlags))
return TRUE;
DWORD dwLastError = GetLastError();
VERIFY(!LocalFree(pqwip));
SetLastError(dwLastError);
return FALSE;
}
As you can see, it is a wrapper around QueueUserWorkItem with an
additional refcount parameter, which should be implemented in each
plugin as a global zero-initialized volatile variable. The thread pool
function SafeThreadProc that it passes to the real QUWI is again
implemented in the exe and looks like so:
static DWORD WINAPI SafeThreadProc(LPVOID lpParam)
{
ASSERT(lpParam);
QUWI_PACKET qwip = *(PQUWI_PACKET)lpParam;
VERIFY(!LocalFree((PQUWI_PACKET)lpParam));
ASSERT((*qwip.m_plRefCount)>=0);
VERIFY(0 < InterlockedIncrement(qwip.m_plRefCount));
DWORD dwRetval = qwip.m_pfnThreadPoolFunc(qwip.m_lpContext);
ASSERT((*qwip.m_plRefCount)>0);
VERIFY(0 <= InterlockedDecrement(qwip.m_plRefCount));
return dwRetval;
}
All that a plugin now has to do is call this function pointer that
points to MAQueueUserWorkItem just like it would call QueueUserWorkItem
and additionally pass it the address of its per-plugin global refcounter
variable. Within the plugin's uninitialization function, it can then do
a semi-busy wait loop until its global refcount has dropped to zero,
like so:
while (g_lRefCount)
{
TRACE(_T("Spinning in a semi-busy loop until all thread pool
functions have finished executing\n"));
Sleep(100);
}
Any comments?
--
Stefan
.
- Follow-Ups:
- References:
- QueueUserWorkItem with functions in a DLL, how to unload safely?
- From: Stefan Kuhr
- Re: QueueUserWorkItem with functions in a DLL, how to unload safely?
- From: Skywing
- QueueUserWorkItem with functions in a DLL, how to unload safely?
- Prev by Date: Re: CD/DVD creation date ?
- Next by Date: Re: QueueUserWorkItem with functions in a DLL, how to unload safely?
- Previous by thread: Re: QueueUserWorkItem with functions in a DLL, how to unload safely?
- Next by thread: Re: QueueUserWorkItem with functions in a DLL, how to unload safely?
- Index(es):
Relevant Pages
|