Creating a way to safely access controls from another thread - c#

I am trying to write a 'SafeInvoke' method that handles all cases/problems that can occur when trying to access a control from another thread. I've seen a lot of solutions and a lot of questions about this and while there are some that are good enough for most people, they all fail to take race conditions in account (meaning that it's still possible to get an unwanted exception).
So this is what I have so far, I tried commenting as best as I could why I put some ifs and try catches. I also tried to catch only the relevant exceptions, InvalidOperationException is one that can occur for a wide range of reasons (including Collection was modified) and I didn't want to suppress those (because they have nothing to do with the safe invoking). To check that I based myself on the TargetSite.Name property of the exception, I also looked up the actual throw in reflector to see if there were any other locations that could cause an exception.
/// <summary>
/// Safely invokes an action on the thread the control was created on (if accessed from a different thread)
/// </summary>
/// <typeparam name="T">The return type</typeparam>
/// <param name="c">The control that needs to be invoked</param>
/// <param name="a">The delegate to execute</param>
/// <param name="spinwaitUntilHandleIsCreated">Waits (max 5sec) until the the control's handle is created</param>
/// <returns>The result of the given delegate if succeeded, default(T) if failed</returns>
public static T SafeInvoke<T>(this Control c, Func<T> a, bool spinwaitUntilHandleIsCreated = false)
{
if (c.Disposing || c.IsDisposed) // preliminary dispose check, not thread safe!
return default(T);
if (spinwaitUntilHandleIsCreated) // spin wait until c.IsHandleCreated is true
{
if (!c.SpinWaitUntilHandleIsCreated(5000)) // wait 5sec at most, to prevent deadlock
return default(T);
}
if (c.InvokeRequired) // on different thread, need to invoke (can return false if handle is not created)
{
try
{
return (T)c.Invoke(new Func<T>(() =>
{
// check again if the control is not dispoded and handle is created
// this is executed on the thread the control was created on, so the control can't be disposed
// while executing a()
if (!c.Disposing && !c.IsDisposed && c.IsHandleCreated)
return a();
else // the control has been disposed between the time the other thread has invoked this delegate
return default(T);
}));
}
catch (ObjectDisposedException ex)
{
// sadly the this entire method is not thread safe, so it's still possible to get objectdisposed exceptions because the thread
// passed the disposing check, but got disposed afterwards.
return default(T);
}
catch (InvalidOperationException ex)
{
if (ex.TargetSite.Name == "MarshaledInvoke")
{
// exception that the invoke failed because the handle was not created, surpress exception & return default
// this is the MarhsaledInvoke method body part that could cause this exception:
// if (!this.IsHandleCreated)
// {
// throw new InvalidOperationException(SR.GetString("ErrorNoMarshalingThread"));
// }
// (disassembled with reflector)
return default(T);
}
else // something else caused the invalid operation (like collection modified, etc.)
throw;
}
}
else
{
// no need to invoke (meaning this is *probably* the same thread, but it's also possible that the handle was not created)
// InvokeRequired has the following code part:
// Control wrapper = this.FindMarshalingControl();
// if (!wrapper.IsHandleCreated)
// {
// return false;
// }
// where findMarshalingControl goes up the parent tree to look for a parent where the parent's handle is created
// if no parent found with IsHandleCreated, the control itself will return, meaning wrapper == this and thus returns false
if (c.IsHandleCreated)
{
try
{
// this will still yield an exception when the IsHandleCreated becomes false after the if check (race condition)
return a();
}
catch (InvalidOperationException ex)
{
if (ex.TargetSite.Name == "get_Handle")
{
// it's possible to get a cross threadexception
// "Cross-thread operation not valid: Control '...' accessed from a thread other than the thread it was created on."
// because:
// - InvokeRequired returned false because IsHandleCreated was false
// - IsHandleCreated became true just after entering the else bloc
// - InvokeRequired is now true (because this can be a different thread than the control was made on)
// - Executing the action will now throw an InvalidOperation
// this is the code part of Handle that will throw the exception
//
//if ((checkForIllegalCrossThreadCalls && !inCrossThreadSafeCall) && this.InvokeRequired)
//{
// throw new InvalidOperationException(SR.GetString("IllegalCrossThreadCall", new object[] { this.Name }));
//}
//
// (disassembled with reflector)
return default(T);
}
else // something else caused the invalid operation (like collection modified, etc.)
throw;
}
}
else // the control's handle is not created, return default
return default(T);
}
}
There is 1 thing I don't know for sure, which is if IsHandleCreated=true, will it ever become false again ?
I added the spinwait for IsHandleCreated because I started Task<>s in the OnLoad event of the control and it was possible that the task was finished before the control was completely finished with loading. If however it takes longer than 5sec to load a control I let the task finish anyway, without updating the GUI (otherwise I'd have a lot of threads spinwaiting for something that probably won't occur anymore)
If you have any suggestions for optimizations or find any bugs or scenario's that might still pose a problem, please let me know :).

Honestly, do you do so may checkings as well when you access a control/from with the UI thread in a basic application? Probably not, you just code and expect the control exists and is not disposed. Why do you that amount of checkings now?
It's not a good idea let multiple threads access the UI, but in case you have no other way I would recommend you to use Control.BeginInvoke. Using Control.BeginInvoke, Control.IsInvokeRequired should be enough.
Actually I've never used Control.IsInvokeRequired, I know before hand which access will come from a different thread and which no.

Related

What happens if I Monitor.Enter conditionally while another thread is in the critical section without a lock?

I'm attempting to reimplement functionality from a system class (Lazy<T>) and I found this unusual bit of code. I get the basic idea. The first thread to try for a value performs the calculations. Any threads that try while that's happening get locked at the gate, wait until release, and then go get the cached value. Any later calls notice the sentinel value and don't bother with the locks any more.
bool lockWasTaken = false;
var obj = Volatile.Read<object>(ref this._locker);
object returnValue = null;
try
{
if (obj != SENTINEL_VALUE)
{
Monitor.Enter(obj, ref lockWasTaken);
}
if (this.cachedValue != null) // always true after code has run once
{
returnValue = this.cachedValue;
}
else //only happens on the first thread to lock and enter
{
returnValue = SomeCalculations();
this.cachedValue = returnValue;
Volatile.Write<object>(ref this._locker, SENTINEL_VALUE);
}
return returnValue
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(obj);
}
}
But let's say, after a change in the code, that another method resets the this._locker to it's original value and then goes in to lock and recalculate the cached value. While it does this, another thread happened to be picking up the cached value, so it's inside the locked section, but without a lock. What happens? Does it just execute normally while the thread with the lock also goes in parallel?
While it does this, another thread happened to be picking up the cached value, so it's inside the locked section, but without a lock. What happens? Does it just execute normally while the thread with the lock also goes in parallel?
Yes, it'll just execute normally.
That being said, this code appears like it could be removed entirely by using Lazy<T>. The Lazy<T> class provides a thread safe way to handle lazy instantiation of data, which appears to be the goal of this code.
Basically, the entire code could be replaced by:
// Have a field like the following:
Lazy<object> cachedValue = new Lazy<object>(() => SomeCalculations());
// Code then becomes:
return cachedValue.Value;

Checking if an object exists after calling Activator.GetObject

I'm developing a project with passive replication where servers exchange messages among themselves. The locations of each server are well-known by every other server.
So, it may happen that when a server comes up, it will check the other servers, that may haven't come up yet. When I call Activator.GetObject, is it the only way to find out that other servers are down by invoking a method on the object, and expect an IOException (such as the example below)?
try
{
MyType replica = (MyType)Activator.GetObject(
typeof(IMyType),
"tcp://localhost:" + location + "/Server");
replica.ping();
}
catch (IOEXception){} // server is down
I do this and it works most of the times (even though is slow), but sometimes it blocks on a method called NegotiateStream.ProcessRead during the process, and I can't understand why...
When a server is down, the timeout has always been slow for me (using a TcpChannel, which doesn't let you set the timeout properly in .NET Remoting). Below is a workaround for how I use my Ping function (it's likely a bit complex for your needs, so I'll explain the parts that matter for you):
[System.Diagnostics.DebuggerHidden] // ignore the annoying breaks when get exceptions here.
internal static bool Ping<T>(T svr)
{
// Check type T for a defined Ping function
if (svr == null) return false;
System.Reflection.MethodInfo PingFunc = typeof(T).GetMethod("Ping");
if (PingFunc == null) return false;
// Create a new thread to call ping, and create a timeout of 5 secons
TimeSpan timeout = TimeSpan.FromSeconds(5);
Exception pingexception = null;
System.Threading.Thread ping = new System.Threading.Thread(
delegate()
{
try
{
// just call the ping function
// use svr.Ping() in most cases
// PingFunc.Invoke is used in my case because I use
// reflection to determine if the Ping function is
// defined in type T
PingFunc.Invoke(svr, null);
}
catch (Exception ex)
{
pingexception = ex;
}
}
);
ping.Start(); // start the ping thread.
if (ping.Join(timeout)) // wait for thread to return for the time specified by timeout
{
// if the ping thread returned and no exception was thrown, we know the connection is available
if (pingexception == null)
return true;
}
// if the ping thread times out... return false
return false;
}
Hopefully the comments explain what I do here, but I'll give you a breakdown of the whole function. If you're not interested, just skip down to where I explain the ping thread.
DebuggerHidden Attribute
I set the DebuggerHidder attribute because when debugging, exceptions can be thrown here constantly in the ping thread, and they are expected. It is easy enough to comment this out should debugging this function become necessary.
Why I use reflection and a generic type
The 'svr' parameter is expected to be a type with a Ping function. In my case, I have a few different remotable interfaces implemented on the server with a common Ping function. In this way, I can just call Ping(svr) without having to cast or specify a type (unless the remote object is instantiated as an 'object' locally). Basically, this is just for syntactical convenience.
The Ping Thread
You can use whatever logic you want to determine an acceptable timeout, in my case, 5 seconds is good. I create a TimeSpan 'timeout' with a value of 5 seconds, an Exception pingexception, and create a new thread that tries to call 'svr.Ping()', and sets 'pingexception' to whatever exception is thrown when calling 'svr.Ping()'.
Once I call 'ping.Start()', I immediately use the boolean method ping.Join(TimeSpan) to wait for the thread to return successfully, or move on if the thread doesn't return within the specified amount of time. However, if the thread finished executing but an exception was thrown, we still don't want Ping to return true because there was a problem communicating with the remote object. This is why I use the 'pingexception' to make sure that no exceptions occurred when calling svr.Ping(). If 'pingexception' is null at the end, then I know I'm safe to return true.
Oh and to answer the question you originally asked (....sometimes it blocks on a method called NegotiateStream.ProcessRead during the process, and I can't understand why...), I have never been able to figure out the timeout issues with .NET Remoting, so this method is what I've baked and cleaned up for our .NET Remoting needs.
I've used an improved version of this with generics:
internal static TResult GetRemoteProperty<T, TResult>(string Url, System.Linq.Expressions.Expression<Func<T, TResult>> expr)
{
T remoteObject = GetRemoteObject<T>(Url);
System.Exception remoteException = null;
TimeSpan timeout = TimeSpan.FromSeconds(5);
System.Threading.Tasks.Task<TResult> t = new System.Threading.Tasks.Task<TResult>(() =>
{
try
{
if (expr.Body is System.Linq.Expressions.MemberExpression)
{
System.Reflection.MemberInfo memberInfo = ((System.Linq.Expressions.MemberExpression)expr.Body).Member;
System.Reflection.PropertyInfo propInfo = memberInfo as System.Reflection.PropertyInfo;
if (propInfo != null)
return (TResult)propInfo.GetValue(remoteObject, null);
}
}
catch (Exception ex)
{
remoteException = ex;
}
return default(TResult);
});
t.Start();
if (t.Wait(timeout))
return t.Result;
throw new NotSupportedException();
}
internal static T GetRemoteObject<T>(string Url)
{
return (T)Activator.GetObject(typeof(T), Url);
}

Does Timer.Change() ever return false?

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.

Return from a Class Execution using an Event or ..?

I'm going to provide a simple example of what I'm trying to do -- hopefully it is possible?
I basically have a class that does a whole ton of formatting/analyzing to the data. As a result, there a lot of things that can go wrong with this. The problem I have is handling the class when things go wrong. I want all execution of this class to stop once an error has occurred.
This class (AnalyzingStuff) is called from a parent form that does various things based on the result of this classes execution.
Ideally, I would fire an event named say "ABORT".
So in this code here I do the following:
Class AnalyzingStuff{
public event EventHandler ABORT;
public AnalyzingStuff(){
for(int i = 0; i < 999999; i ++){
AnalyzeSomeStuff();
AnalyzerSomeOtherStuff();
}
MoreStuff();
OtherStuff();
}
private void AnalyzeSomeStuff(){
if(someconditionNotMet){
//EXIT OUT OF THIS CLASS, STOP EXECUTION!!!
this.ABORT.Invoke(this, null);
}
}
}
Calling this 'ABORT' event, I would stop the execution of this class (stop the loop and not do anything else). I could also catch this event handler in some other parent form. Unfortunately, I can't find any way of stopping the execution of this class.
Ideas so far:
The obvious answer is to simply set a flag and constantly check this flag over and over in multiple places, but I really don't like this approach (my current implementation). Having to check this after every single method call (there are MANY) is ugly codewise.
I thought maybe a background worker or something where you could cancel the execution of the DoWork?
Use a form as a base class for the AnalyzingStuff so I can simply call "this.Close();".
What do you think is the best approach to this situation? Are these the best solutions? Are there any other elegant solutions to what I want here or am I going completely in the wrong direction?
EDIT: I have a series of try/catch blocks used throughout this code that is used to handle different errors that can occur. Unfortunately, not all of them call for an Abort to occur so they need to be caught immediately. Therefore, try/catch not the most ideal approach.. or is it?
Don't do analysys in the constructor. Do it in a main Analyze() method.
Use exceptions. If you want to abort because of a fatal error, throw a fatal exception. That is, throw an exception that you don't catch within the scope of the main analysis method.
class Analyzer
{
public Analyzer()
{
// initialize things
}
public void Analyze()
{
// never catch a fatal exception here
try
{
AnalyzeStuff();
... optionally call more methods here ...
}
catch (NonFatalException e)
{
// handle non fatal exception
}
... optionally call more methods (wrapped in try..catch) here ...
}
private void AnalyzeStuff()
{
// do stuff
if (something nonfatal happens)
throw new NonFatalException();
if (something fatal happens)
throw new FatalException();
}
}
outside:
{
var analyzer = new Analyzer();
try
{
analyzer.Analyze();
}
catch (FatalException)
{
Console.WriteLine("Analysis failed");
}
}
If you don't like using exception this way, you can accomplish the same thing by having every analysis method return a bool:
if (!AnalyzeStuff())
return false;
if (!AnalyzeMoreStuff())
return false;
...
return true;
But you end up with a lot of return statements or a lot of braces. It's a matter of style and preference.
Could you throw an Exception if things go wrong, and run a try catch around where you call the method in the loop?
if you do this you could do stuff if the class fails (which you will put in the catch), and stuff you could do to close connections to database ++ when it is done.
or you could make the methods return an int, to tell if the execution of the method was valid. ex. return 0; is valid execution, return 1-500 would then might be different error codes. Or you might go for the simple version of passing a bool. If you need to return values from methods other than the error code you could pass these as OUT variables. example following:
Class AnalyzingStuff{
public AnalyzingStuff(){
for(int i = 0; i < 999999; i ++){
if (!AnalyzeSomeStuff() || !AnalyzerSomeOtherStuff())
break;
}
MoreStuff();
OtherStuff();
}
private bool AnalyzeSomeStuff(){
if(someconditionNotMet){
return false;
}
return true;
}
}
You can of course use your event. I just removed it for the simplicity of it.

Stop method execution

I have a class that tries to get information from web service few times:
public TResult Try(Func<TResult> func, int maxRetries)
{
TResult returnValue = default(TResult);
int numTries = 0;
bool succeeded = false;
while (numTries < maxRetries)
{
try
{
returnValue = func();
succeeded = true;
}
catch (Exception ex)
{
Log(ex,numTries);
}
finally
{
numTries++;
}
if (succeeded)
{
return returnValue;
}
else
{
if (numTries == maxRetries)
{
//ask user what to do
}
}
}
Now after 'if (numTries == maxRetries)' user will be able to chose if he wants to continue trying to get data from web service or cancel.
I want to just open new form when user cancels and stop executing method that called above method. I can't just return null or new object because the method that run this retrier will continue to work and in many cases cause problems.
So basically this looks like this:
someValue = retry.Try(() => webService.method(),maxRetries));
//if user canceled after app wasn't able to get data stop execution as already another form is opened
I could of course check if returned value was null like:
someValue = retry.Try(()=>webService.method(),maxRetries));
if (someValue == null)
return;
But this would mean a lot of changes in the code and I want to avoid it and it would be best if I could do it from Try method.
I can think of two things. You could make sure that TResult is of an Interface type that has a Boolean field that represents a successful request (IsSuccessful or IsValid, etc). If you cannot modify TResult, the other option is to use an Out parameter on your try method to pass another value out.
There is no way to just stop the execution of a method. The first thing that comes to mind though is to throw an exception and catch it from the calling method.
Keep in mind though that you shouldn't ever rely on exceptions to control flow like that.. but if you really can't rewrite the calling method, this may be your only option.
The other option is perhaps having your returned result set a flag (via an interface) to notify the caller that it completed successfully.

Categories

Resources