I have a object of CCriticalSection in my class to synchronize the exceptions to a method. I use it with CSingleLock object like this:
void f()
{
try
{
CSingleLock lock(&m_synchronizer, TRUE);
.....
.....
}
catch(SomeException )
{
}
catch(...)
{
}
}
The critical section object is properly unlocked if any of the statement throws a C++ exception, however if I get any other type of exception (something like a access violation) is there any way I can unlock my critical section? I don't think RAII will help here as the stack unwinding doesn't happen. Is there any thing I can do to prevent the critical section being in locked state after exiting the function f?
-
RAII does help here. The most important thing to not here is "going out of scope" is not necessarily just stack unwinding. When the try block is exited, either normally or through an exception, the destructor will be called. Anytime your variable goes out of scope its destructor is invoked.
Edit
Hmm it appears the question has been edited to focus on SEH (non C++ exceptions). In this case the destructor code might not be fired. However, as others have pointed out, most of the non-C++ exceptions are equivalent to application crashes. It may not be reasonable to react to these exceptions in any sane way other than to crash. In this case your app is exited and your critical section will be destroyed anyway.
See @JaredPar's answer for a good solution for translating C SEH exceptions to C++ exceptions for Windows.
Naveen : I don't think the destructor of lock object will be called in case of structured exceptions.JaredPar : @Naveen, this depends on your compiler settings. They will be called if you enable ASYNC exception handling.Richard : @Naveen, C++ exceptions are SEH exceptions. The only difference between catch and __catch is the former will only catch a subset of cases. In any case, why not test?Michael Burr : @Richard - C++ exceptions are *not* structured exceptions, though the compiler has the option to turn SEH exceptions into C++ exceptions. -
EDIT Update
The destructor of CSingleLock will indeed unlock the underlying critical section. Access violations and the like are called SEH exceptions. As to whether or not the destructor will run in the face of an SEH exception is very environment specific. There are tricks you can do to make this type of scenario work.
For instance, one option is to translate all SEH exceptions into a corresponding C++ exception. I blogged recently on the technique to accomplish this. Once they're all C++ exceptions then the destructor being called is guaranteed.
But another question is why bother doing this? Once you're faced with at access violation the only thing your program can reliably do is crash.
Naveen : Even CSingleLock does it. Isn't it?JaredPar : @Naveen, looking into that. I'm unfamiliar with that class (spent more of my time with the ATL versions).Michael Burr : Looks like a nice blog article on this - I'll have to read it more closely later. However, catching and handling SEH exceptions can be useful, especially for validating parameters (and especially when dealing with being called from untrusted code, such as plugins). You can return an error instead of crashing in this case, and do it reliably. At least reasonably reliably.Doug T. : Very nice article @JaredPar. +1.Doug T. : nice blog @JaredPar, glad to know at least 2 out of 4 of the answers to this question were entered via Dvorak. Fight the power!Martin York : But even if you crash, some resources are so limited/critical that they absolutely must be released (and correctly) (That up-link to the ISS for instance). In these cases it would be very useful to force stack unwinding with a C++ exception.JaredPar : @Martin, are you talking about Mutex instances shared across process's? If so, the process exit should cause the OS to free the locks appropriately. I know Windows will and I'm fairly certain *nix does as well (been awhile though so I can't speak absolutely). Is there a difference type of resource you're talking about that I'm missing? -
Assuming you're using MSVC try compiling with the
/EHacommand line option which maps Windows' structured exceptions to C++ exceptions (the C++ docs sometimes call them 'asynchronous' exceptions).You should read up on the implications of this - I don't use the option myself, and I'm not sure what the drawbacks might be.
You could also try using the
__try,__except,__finallykeywords to handle SEH yourself.James Hopkin : If you use __try etc., it won't let you create any object with non-trivial destructors in that functionMichael Burr : Ah - then you're stuck with either using /EHa, doing a lot of restructuring of code, or using something like what JaredPar wrote about on his blog. -
If you really need your application to survive when a particular area of code performs an access violation, you should consider having that code in a separate process.
If code is trying to read or write to places it's not allowed, what's to stop it writing into other parts of your application's memory, causing all sorts of nasty problems?
-
AFAIK, you NEVER should use CCriticalSection nor any MFC synchronization object.
0 comments:
Post a Comment