Monday, January 3, 2011

Multithreading with ArcObjects

 

Multithreading should be discouraged with ESRI code simply because of the usage of COM classes, typically you will get COM exceptions saying that the RCW is no longer connected to the COM class.

But if you still want to implement multithreading within your application then you got to right place.

Things that must be considered:

1.       Licensing – calling:

RuntimeManager.Bind(ProductCode.Server)

If you call it twice you might get an exception that you don't have any free license (that will happen in both single threaded and multithreaded applications).

2.        IWorkspace – you can't use the workspace you initialized in a different thread – COM exception (RCW).

3.       All singleton objects created in your application might not work if they use a saved ESRI object (for example I have a WorkspaceProvider factory class that caches IWorkspace by their connection string for reuse).

4.       STA (single threaded apartment) vs MTA (multithreaded apartment) – you can mark a static method as either [STAThread] or [MTAThread], and for each the threading apartment used is different. ArcObjects use the STA the .NET default is (of course) MTA meaning any time you want to use a static method you should use it with the STA attribute.

5.       Singleton classes that save inner ArcObjects variables (as opposed to providing methods like a utils class) should also save the thread id and when the current thread id is different reload the variables. Otherwise prepare yourself and catch the incoming COM exception (RCW).

The simplest way of doing multithreading with ArcObjects is not doing it at all. Nice – but how? Implement a web/WCF service that talks with ArcObjects and within your multithreaded application call that service. An important note though is that a web/WCF service needs ArcGIS Server license (see Upgrading the code base from ArcGIS 9.3.1 to 10).

You might think this is simple until you realize that WCF sitting on IIS is multithreaded by design.

The simplest solution is to always use newly created objects. In this case though the simplest way is also the slowest since sometimes the IWorkspace can be used for several feature layers/tables and recreating this object takes time.

The code I use has a singleton factory class that handles the creation of IWorkspace classes. The only fix you need to add is mark the instance of that factory with the ThreadStaticAttribute attribute.

//TODO: add example

//TODO: continue this post

//TODO: the font formatting is off

 

 

References:

Writing multithreaded ArcObjects code

http://gis.stackexchange.com/questions/2490/accessing-arcgis-layers-from-seperate-thread

http://gis.stackexchange.com/questions/2688/possible-cause-of-accessviolation-in-arcobject-multithreaded-app

http://funcode.org/article/csharp/creating-per-thread-static-fields.aspx