I was using Reflector to peruse some of the source for the .Net ThreadPool, when it showed this:
private static bool QueueUserWorkItemHelper(WaitCallback callBack, object state, ref StackCrawlMark stackMark, bool compressStack)
{
bool flag = true;
if (callBack == null)
{
throw new ArgumentNullException("WaitCallback");
}
EnsureVMInitialized();
if (ThreadPoolGlobals.useNewWorkerPool)
{
try
{
return flag;
}
finally
{
QueueUserWorkItemCallback callback = new QueueUserWorkItemCallback(callBack, state, compressStack, ref stackMark);
ThreadPoolGlobals.workQueue.Enqueue(callback, true);
flag = true;
}
}
// code below here removed
}
The try/finally block struck me as very unidiomatic C#. Why write it like this? What is the difference if you got rid of the try/finally and moved the return to the end?
I understand how Reflector works and that this might not be the original source. If you think that's the case, can you suggest what the original source might have been?
Microsoft has published the source to .NET - though I still use Reflector due to easier browsing. This is the actual code snippet from .NET 4.0.
//
// If we are able to create the workitem, we need to get it in the queue without being interrupted
// by a ThreadAbortException.
//
try { }
finally
{
QueueUserWorkItemCallback tpcallBack = new QueueUserWorkItemCallback(callBack, state, compressStack, ref stackMark);
ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, true);
success = true;
}
Actually, this empty try block and code in finally block pattern is described in the Jeffrey Richter's book "CLR via C#".
The thing is that if something goes wrong and thread is aborted the finally blocks are guaranteed to execute. At least they are more likely to execute than try blocks. For more details you should look in the section of mentioned book which describes exceptions and error handling
Related
I noticed in System.Threading.TimerBase.Dispose() the method has a try{} finally{} block but the try{} is empty.
Is there any value in using try{} finally{} with an empty try?
http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
bool status = false;
bool bLockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
}
finally {
do {
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
bLockTaken = true;
try {
status = DeleteTimerNative(notifyObject.SafeWaitHandle);
}
finally {
m_lock = 0;
}
}
Thread.SpinWait(1);
// yield to processor
}
while (!bLockTaken);
GC.SuppressFinalize(this);
}
return status;
}
From http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/:
This methodology guards against a
Thread.Abort call interrupting the
processing. The MSDN page of
Thread.Abort says that “Unexecuted
finally blocks are executed before the
thread is aborted”. So in order to
guarantee that your processing
finishes even if your thread is
aborted in the middle by someone
calling Abort on your thread, you can
place all your code in the finally
block (the alternative is to write
code in the “catch” block to determine
where you were before “try” was
interrupted by Abort and proceed from
there if you want to).
This is to guard against Thread.Abort interrupting a process. Documentation for this method says that:
Unexecuted finally blocks are executed before the thread is aborted.
This is because in order to recover successfully from an error, your code will need to clean up after itself. Since C# doesn't have C++-style destructors, finally and using blocks are the only reliable way of ensuring that such cleanup is performed reliably. Remember that using block turns into this by the compiler:
try {
...
}
finally {
if(obj != null)
((IDisposable)obj).Dispose();
}
In .NET 1.x, there was a chance that finally block will get aborted. This behavior was changed in .NET 2.0.
Moreover, empty try blocks never get optimized away by the compiler.
The .NET System.Threading Timer class has several overloaded Change() methods that return "true if the timer was successfully updated; otherwise, false."
Ref: http://msdn.microsoft.com/en-us/library/yz1c7148.aspx
Does this method ever actually return false? What would cause this to return false?
Joe Duffy (the development lead, architect, and founder of the Parallel
Extensions to the .NET Framework team at Microsoft) detailed in Concurrent Programming on Windows p 373
Note that although Change is typed as returning a bool, it will actually never return anything but true. If there is a problem changing the timer-such as the target object already having been deleted-an exception will be thrown.
This can in fact return false if the unmanaged extern ChangeTimerNative were to return false. However, this is awfully unlikely.
Take note to Microsoft's code:
bool status = false;
bool bLockTaken = false;
// prepare here to prevent threadabort from occuring which could
// destroy m_lock state. lock(this) can't be used due to critical
// finalizer and thinlock/syncblock escalation.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
finally
{
do
{
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0)
{
bLockTaken = true;
try
{
if (timerDeleted != 0)
throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
status = ChangeTimerNative(dueTime,period);
}
finally
{
m_lock = 0;
}
}
Thread.SpinWait(1); // yield to processor
}
while (!bLockTaken);
}
return status;
PLEASE NOTE that the ChangeTimerNative calls the ChangeTimerQueueTimer Windows API function so you can read that documentation to get a feel for how it might fail.
On checking the managed source, the only case in which it returns false is if the AppDomain timer (if one does not exist, it is created) represented by a private class AppDomainTimerSafeHandle - has SafeHandle.IsInvalid set to true.
Since AppDomainTimerSafeHandle inherits from SafeHandleZeroOrMinusOneIsInvalid, IsInvalid is implemented by it - when a timer is attempted to be created by the unmanaged infrastructure and ends up with a Safe-Handle which is reading from the definition Zero-Or-Minus-One-Is-Invalid.
All cases point to this being extremely unlikely.
Here is my code:
internal void Show()
{
if (Parent == null)
throw new NullReferenceException();
EDITBALLOONTIP ebt = new EDITBALLOONTIP();
ebt.cbStruct = Marshal.SizeOf(ebt);
ebt.pszText = Text;
ebt.pszTitle = Caption;
ebt.ttiIcon = (int)Icon;
IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ebt));
Marshal.StructureToPtr(ebt, ptrStruct, true); // Here we go.
// Access violation exception in Windows 7 + .NET 4.0
// In Windows XP + .NET 3.5, it works just fine.
// ... Some other code ...
Marshal.FreeHGlobal(ptrStruct);
}
And here is the structure:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct EDITBALLOONTIP
{
internal int cbStruct;
internal string pszTitle;
internal string pszText;
internal int ttiIcon;
}
Why does this work fine in Windows XP + .NET 3.5 and raises exceptions in Windows 7 + .NET 4.0? May be it's CharSet trouble?
=====================Solved=======================
Solution and explanation
As you can see Marshal.StructureToPtr(ebt, ptrStruct, true); has third parameter set to true. It means that the system will try to free the last allocated memory for ptrStruct. But when method Show() is invoked for the first time, there was not allocated memory for that structure (ptrStruct = IntPtr.Zero). So system will try to free memory located at zero pointer. And of course it will raise an exception. Windows XP just ignores this, but Windows 7 doesn't.
And here is best solution IMHO:
Marshal.StructureToPtr(ebt, ptrStruct, false);
//Working...
//Free resources
Marshal.FreeHGlobal(ptrStruct);
I didn't want to add an answer here as you already have solved your problem and what I'll say won't provide any answer to the problem you had, but it wouldn't fit well as a comment as I provide some code.
So I'm obliged to post it here as an answer.
You may already know it (and didn't wrote it that way so the code in your question is simpler), but I just wanted to say that a best practice that should be used everywhere when unmanaged memory is allocated, is to encapsulate the code in a try/finally block to ensure the memory is always freed, even if an exception is thrown:
private static void Test()
{
IntPtr ptrStruct = IntPtr.Zero;
try
{
Marshal.AllocHGlobal(0x100);
// Some code here
// At some point, an exception is thrown
throw new IndexOutOfRangeException();
}
finally
{
// Even if the exception is thrown and catch
// from the code that calls the Test() method,
// the memory will be freed.
if (ptrStruct != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptrStruct);
}
}
}
try
{
Test();
}
catch (IndexOutOfRangeException)
{
// Catches the exception, so the program won't crash
// but it'll exit the Test() method, so the try/finally
// ensures it won't leave without freeing the memory
Debugger.Break();
}
I have a static class which is accessed by multiple threads and uses a ReaderWriterLockSlim in various methods to maintain thread safety. This works fine most of the time, however very intermittently I'm seeing an IOException handle is invalid error being thrown by one particular method as shown in the stack trace below. This has me greatly confused as I didn't even know that System.IO was involved in a ReaderWriterLock.
Any help at all in understanding where the error may be comming from would be greatly appreciated.
Stack Trace:
System.IO.IOException: The handle is invalid.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.Threading.EventWaitHandle.Reset()
at System.Threading.ReaderWriterLockSlim.WaitOnEvent(EventWaitHandle waitEvent, UInt32& numWaiters, Int32 millisecondsTimeout)
at System.Threading.ReaderWriterLockSlim.TryEnterUpgradeableReadLock(Int32 millisecondsTimeout)
Code:
class Class1
{
private static ReaderWriterLockSlim readwriteLock = new ReaderWriterLockSlim();
private const int readwriterlocktimeoutms = 5000;
private static void myMethod(int ID)
{
bool IsTaken = false;
bool isWriteLockTaken = false;
if (!readwriteLock.TryEnterUpgradeableReadLock(readwriterlocktimeoutms))
{
throw new Exception("SafeGetSuItem: Error acquiring read lock");
}
else { IsTaken = true; }
try
{
// do some work which may require upgrading to a write lock depending on particular conditions
}
finally
{
if (IsTaken)
{
try
{
readwriteLock.ExitUpgradeableReadLock();
IsTaken = false;
}
catch
{
throw;
}
}
}
}
}
enter code here
bool IsWriteTaken = false;
try
{
if (!readerwriterlock.TryEnterWriteLock(readerwriterlocktimeout))
{
// log the error
}
else
{
IsWriteTaken = true;
}
if (IsWriteTaken)
{
// do some work
}
}
finally
{
if (IsWriteTaken)
{
try
{
readerwriterlock.ExitWriteLock();
}
catch
{
throw;
}
}
}
This is a little weird. You may have stumbled upon a bug in the WaitHandle class. I picked this apart via Reflector and this is what I am seeing.
Calling Dispose on the ReaderWriterLockSlim will call Close on the EventWaitHandle listed in the stack trace.
Calling Close on a EventWaitHandle attempts to dispose the underlying SafeHandle.
Calling Reset on a EventWaitHandle calls directly into the ResetEvent Win32 API from kernel32.dll and passes in the SafeHandle.
I see no synchronization mechanisms in place that prevent a race between the disposing of a SafeHandle and having that instance consumed by the Win32 API.
Are you calling Dispose on the ReaderWriterLockSlim instance from another thread while TryEnterUpgradeableReadLock could be executing? This seems like the most likely scenario to me. Actually, this is the only scenario that I am seeing that would lead to an IOException being thrown.
It seems to me, based solely on my cursory analysis of the BCL code, that the IOException could be by-design, but it would make a whole lot more sense if Microsoft could somehow generate a ObjectDisposedException instead which happens on every single other attempt I have made to reproduce the problem. I would go ahead and report this to Microsoft.
I noticed in System.Threading.TimerBase.Dispose() the method has a try{} finally{} block but the try{} is empty.
Is there any value in using try{} finally{} with an empty try?
http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
bool status = false;
bool bLockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
}
finally {
do {
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
bLockTaken = true;
try {
status = DeleteTimerNative(notifyObject.SafeWaitHandle);
}
finally {
m_lock = 0;
}
}
Thread.SpinWait(1);
// yield to processor
}
while (!bLockTaken);
GC.SuppressFinalize(this);
}
return status;
}
From http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/:
This methodology guards against a
Thread.Abort call interrupting the
processing. The MSDN page of
Thread.Abort says that “Unexecuted
finally blocks are executed before the
thread is aborted”. So in order to
guarantee that your processing
finishes even if your thread is
aborted in the middle by someone
calling Abort on your thread, you can
place all your code in the finally
block (the alternative is to write
code in the “catch” block to determine
where you were before “try” was
interrupted by Abort and proceed from
there if you want to).
This is to guard against Thread.Abort interrupting a process. Documentation for this method says that:
Unexecuted finally blocks are executed before the thread is aborted.
This is because in order to recover successfully from an error, your code will need to clean up after itself. Since C# doesn't have C++-style destructors, finally and using blocks are the only reliable way of ensuring that such cleanup is performed reliably. Remember that using block turns into this by the compiler:
try {
...
}
finally {
if(obj != null)
((IDisposable)obj).Dispose();
}
In .NET 1.x, there was a chance that finally block will get aborted. This behavior was changed in .NET 2.0.
Moreover, empty try blocks never get optimized away by the compiler.