Click or drag to resize

Reliability

Overview

This section presents information on how to make the application robust. The most important mechanism related to robustness and reliability is error handling. Avoiding thread conflicts and memory leaks are however also important means of improving reliability.

Error handling in .NET applications

As already pointed out in this manual, Microsoft recommends that exceptions are used to discover and report anomalities in .NET applications. If you are not sure about when to use exceptions or how to do the implementation you should read Exception handling to understand the general idea before moving on to the FlexPendant specific information of this section.

SDK exception classes

The ABB.Robotics namespace provides quite a few exception classes, used by the FlexPendant SDK and SDK applications. In addition, the SDK also uses System exceptions and may throw a System.ArgumentException object for example.

Whenever an exception is thrown, your application must catch it and take proper action. You catch an exception by using the try-catch(-finally) statements. For more information about how to implement these statements, see Exception handling.

As you see in the following image GeneralException derives from BaseException, which in turn derives from System.ApplicationException of the .NET Framework class library.

ApplicationException is thrown by user programs, such as the FlexPendant SDK, not by the Common Language Runtime (CLR, for more information, see Definitions ). It therefore represents a way to differentiate between exceptions defined by applications versus exceptions defined by the system.

As you see there are derived types under GeneralException. The following table lists and briefly describes these types:

7.4 1 General Exceptionnamespace
Tip Tip

For more information on FlexPendant SDK exception classes, see Reference Manual FlexPendant SDK.

Thread affinity

You should be aware that execution of code modifying the user interface, has to be done on the thread that created the GUI control, the so called GUI thread.

An application initially starts with a single thread. Normally all user interface controls are created by this thread. Windows CE user interface objects are characterized by thread affinity, which means that they are closely coupled with the thread that created them.

Interacting with the message queue of an interface control from a thread other then the creating thread may cause data corruption or other errors. This restriction applies to the thread pool as well as to explicitly created threads.

When executing on a secondary thread, a so called worker thread, an update of the user interface must therefore be done very carefully, enforcing a switch to the GUI thread. This is in fact a very common scenario, as controller events use their own threads and should often be communicated to the end user by a GUI update.

Note Note

Thread affinity is especially relevant as for robot controller events, as these by default execute on a background thread. For more information and code samples, see Controller events and threads. The following section also deals with the same issue.

Invoke

In order to execute a method on the GUI thread Control.Invoke can be used. It should however be done carefully, as it makes a synchronous call to the specified event handler, which blocks execution until the GUI thread has finished executing the method. All concurrent calls to Invoke will be queued and executed in their queue order by the GUI thread. This could easily make the GUI less responsive.

There is now an asynchronous version of Invoke, which should be used instead whenever possible. TpsControl.BeginInvokeis a non blocking method, which lets the worker thread continue execution instead of waiting for the GUI thread to have processed the method

Remember that Invoke as well as BeginInvoke should only be used on code that modifies the user interface. You should keep the execution on the background thread as long as possible.

Note Note

If your code tries to access a GUI control from a background thread the .NET common language runtime will throw a System.NotSupportedException.

Memory leaks

As FlexPendant applications are supposed to run without interruption, no memory leaks can be permitted. It is your responsibility to properly clean up and call Dispose. Take your time studying How to avoid memory leaks , Memory management and Technical overview of the FlexPendant device.

Utilizing multi-threading

Threading enables your program to perform concurrent processing so you can do more than one operation at a time. For example, you can use threading to monitor input from the user, and perform background tasks simultaneously. The System.Threading namespace provides classes and interfaces which enable you to easily perform tasks such as creating and starting new threads, synchronizing multiple threads, suspending threads and aborting threads.

The classes Thread and ThreadPool can be used to execute methods on a worker thread. Use ThreadPool for temporary usage of a background thread when a task is meant to terminate fairly soon. Use Thread only for background work that will persist, for example a thread that fetches data from the controller continuously.

There are two timers available in .NET CF that can be used to execute methods periodically at specified intervals. There is however, an important difference between these. The System.Threading.Timer executes the method on a background thread, while the System.Windows.Forms.Timer executes the method on the UI thread.

Note Note

Use System.Threading.Timer if you want to poll data from the controller in order to reduce the load on the GUI thread.

Lock statement

The lock statement is used in multi-threaded applications to make sure access to a part of the code is made by one thread exclusively. If a second thread attempts to lock code which has already been locked by another thread, it must wait until the lock is released.

Remember to limit the code segment that you want to control, that is, only lock what is absolutely necessary to make the code thread safe:

          Object thisLock = new Object();
          lock (thisLock)
          {
          // Critical code section
          }
        

Deadlocks must be avoided. They can occur if more than one lock is used. If more than one lock object must be held, they must always be locked and released in the same order, wherever they are used.

Note Note
If a deadlock occurs, the FlexPendant system will hang. If this happens you should attach the device to the Visual Studio debugger and study the call stack of the threads in the Threads window.
Caution note Caution
Using the lock statement in combination with a call to Invoke is a potential cause to deadlock situations, since Invoke is a blocking call. In short, be careful if you use locks!
Multicast delegates

If a multicast delegate is executed, the execution of the delegates is terminated if an exception is thrown by one of the delegates. It means that the remaining delegates in the list will not be executed if an exception is thrown. This situation can cause erratic behavior, which may be tricky to trace and debug.

Therefore, if you have numerous delegates which are to execute as the result of the same event, you may want to implement the GetInvocationList method. It retrieves a list with a copy of the delegates. This list can be iterated and each delegate called directly:

C#
          private void OnChange()
          {
          Delegate[] evtHandlers = null;

          lock (_lockobj)
          {
          if (_changeHandler != null)
          evtHandlers = _changeHandler.GetInvocationList();
          }
          if (evtHandlers !=null)
          {
          For (int i = 0; i <evtHandlers.Length; i++)
          {
          Delegate d = evtHandlers[i];
          try
          {
          ((EventHandler)d) (this, new EventArgs());
          }
          catch (System.Exception e)
          {
          ABB.Robotics.Diagnostics.Debug.Assert(false, string.Format("Exveption in OnChange:(0)",e.ToString()));
          ABB.Robotics.Diagnostics.Trace.WriteLine(string.Format("Exveption in OnChange:(0)",e.ToString()));
}
}
}
}