B
Bric
I have been looking for ways to prevent asynchronous
Thread.Abort calls from wreaking havoc in my code. I'm
working on an assembly, implemented in Managed Extensions
for C++, that makes unmanaged calls and often needs to
free resources associated with those calls:
bool allocated = false;
try
{
...
// Allocate some resources in unmanaged code
allocated = AllocateUnmanagedResources();
...
}
__finally
{
// Only free resources if allocation was successful
if (allocated)
FreeUnmanagedResources();
}
This code should work fine if the thread running it is not
aborted. However, asynchronously aborting the thread can
lead to two problems:
- The ThreadAbortException can be thrown from inside the
__finally block, causing the resources to be leaked. This
possibility is noted in the Thread.Abort documentation.
- The ThreadAbortException can be thrown after a
successful call to AllocateUnmanagedResources but before
the assignment to the boolean variable. In that case, the
code in the __finally block isn't aware of the current
state, so the resources are leaked.
Both of these scenarios seem to be the result of
deficiencies in the .NET Framework and/or CLR:
1) __finally blocks aren't guaranteed to run to completion
2) There doesn't seem to be a way to create
an "unabortable" block of code. Obviously, this kind of
feature could be abused (and would preclude the need for
(1) above), but it seems necessary in order to allow clean-
up code to know the state of the application.
Anyway, I'm looking for ways to eliminate the race
conditions described above. So far, the only solution
I've found is to surround the whole block with a
try/catch, and push the state variable assignment into
unmanaged code (which can't be aborted):
#pragma unmanaged
// Error-checking ignored for clarity
void AllocationWrapper(bool* pAllocated)
{
*pAllocated = AllocateUnmanagedResources();
}
void DeallocationWrapper(bool* pAllocated)
{
if (*pAllocated)
{
FreeUnmanagedResources();
*pAllocated = false;
}
}
#pragma managed
bool allocated = false;
try
{
try
{
...
AllocationWrapper(&allocated);
...
}
__finally
{
DeallocationWrapper(&allocated);
}
}
catch (ThreadAbortException*)
{
DeallocationWrapper(&allocated);
}
Can anyone think of a cleaner way to remove the race
conditions? Something in the language or framework I've
missed? A configuration setting that magically disables
Thread.Abort?
Thanks...
Thread.Abort calls from wreaking havoc in my code. I'm
working on an assembly, implemented in Managed Extensions
for C++, that makes unmanaged calls and often needs to
free resources associated with those calls:
bool allocated = false;
try
{
...
// Allocate some resources in unmanaged code
allocated = AllocateUnmanagedResources();
...
}
__finally
{
// Only free resources if allocation was successful
if (allocated)
FreeUnmanagedResources();
}
This code should work fine if the thread running it is not
aborted. However, asynchronously aborting the thread can
lead to two problems:
- The ThreadAbortException can be thrown from inside the
__finally block, causing the resources to be leaked. This
possibility is noted in the Thread.Abort documentation.
- The ThreadAbortException can be thrown after a
successful call to AllocateUnmanagedResources but before
the assignment to the boolean variable. In that case, the
code in the __finally block isn't aware of the current
state, so the resources are leaked.
Both of these scenarios seem to be the result of
deficiencies in the .NET Framework and/or CLR:
1) __finally blocks aren't guaranteed to run to completion
2) There doesn't seem to be a way to create
an "unabortable" block of code. Obviously, this kind of
feature could be abused (and would preclude the need for
(1) above), but it seems necessary in order to allow clean-
up code to know the state of the application.
Anyway, I'm looking for ways to eliminate the race
conditions described above. So far, the only solution
I've found is to surround the whole block with a
try/catch, and push the state variable assignment into
unmanaged code (which can't be aborted):
#pragma unmanaged
// Error-checking ignored for clarity
void AllocationWrapper(bool* pAllocated)
{
*pAllocated = AllocateUnmanagedResources();
}
void DeallocationWrapper(bool* pAllocated)
{
if (*pAllocated)
{
FreeUnmanagedResources();
*pAllocated = false;
}
}
#pragma managed
bool allocated = false;
try
{
try
{
...
AllocationWrapper(&allocated);
...
}
__finally
{
DeallocationWrapper(&allocated);
}
}
catch (ThreadAbortException*)
{
DeallocationWrapper(&allocated);
}
Can anyone think of a cleaner way to remove the race
conditions? Something in the language or framework I've
missed? A configuration setting that magically disables
Thread.Abort?
Thanks...