# Access Violation in ArcObject Multi-threaded Application

I think I have figured it out. The most probable cause of exception in Multithreaded application may be:

When both threads trying to open same featureclass it breaks: coz one of the thread is already in the process of opening it and other tries to do the same, So it gives error like:

"Memory could not be read or write from protected memory"

This is my guess, but what wonders me is that why there is no separation of concern, even if I am opening a different workspace in each thread. May be Arcobjects internally, looks for same address space for any object in database. I have written few lines of code and tried to run it with different threads opening different object classes and this also breaks but
whenver, I deligate few thread to open same featureclass it breaks with the above errors.

Also, not releasing memory is the other cause for such errors as well.

Any suggestions?

Adding some code for more clarification:

private void ReadFeatureClass(string featureclassname)
{
IWorkspaceFactory workspaceFactory = new SdeWorkspaceFactory();

IPropertySet connectionProperties = new PropertySet();
connectionProperties.SetProperty("SERVER",settings.Server);
connectionProperties.SetProperty("INSTANCE", Settings.Instance);
connectionProperties.SetProperty("USER", settings.User);
connectionProperties.SetProperty("VERSION", settings.Version);

FeatureWorkspace featureWorkspace = workspaceFactory.Open(connectionProperties, 0) as IFeatureWorkspace;

ITable featureClass = featureWorkspace.OpenTable(featureClassName);
}


Above code breaks with the said exception most of the time.

@AndOne, I am using oracle spatial direct connect. Also, I created a new feature class and ran the same code against it, this also fails when threads are increased. There are few differences which I could figure out between these two featureclasses:

Any suggestions?

-
Could also be a problem caused by garbage collection. One thread garbage collecting objects that another thread also needs. Also see the docs on multi-threading: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/… –  MathiasWestin Oct 19 '10 at 13:54
Collecting objects created in same thread, can it be a problem –  adhiman Oct 20 '10 at 7:17
Try using activator instead of "new" for the workspacefactory. "In ArcObjects, singleton objects require instantiation through the Activator class" ... resources.esri.com/help/9.3/arcgisengine/dotnet/… –  Kirk Kuykendall Oct 20 '10 at 13:05
singleton example here: resources.esri.com/help/9.3/arcgisengine/dotnet/… –  Kirk Kuykendall Oct 20 '10 at 13:07
@adhiman, Yes, you can get strange problems when garbage collection is removing objects that you still have a reference to, if the COM object is sharing some kind of state removing one object might destroy another. I've had similar problems when working with event handlers and with the singleton objects. The we were not able to use the singletons with less then creating true .Net singleton methods of our own that kept a reference to the AO-singleton object. –  MathiasWestin Oct 20 '10 at 15:06

It could potentially be the WorkspaceFactory object. That is a singleton object that may be causing problems for you.

-
Additional reference for singleton objects in ArcGIS: help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/… –  Adam Armour Oct 19 '10 at 15:54
WorkspaceFactory is Singleton per thread and not per process. I am instantiating a Workspacefactory inside each thread. Does it make any difference? –  adhiman Oct 20 '10 at 6:51

When you create ArcObjects objects, they must be created on the main Thread of the Process that loaded the AO binary resource.

You can safely pass reference to the IApplication instance between threads, and cast that to IObjectFactory in order to safely create instances of AO objects.

-
I think this way we will not be able to achieve "Threads in isolation model", as suggested by ESRI.Can you share any example? –  adhiman Oct 20 '10 at 6:45

...For ArcObjects applications to run efficiently in a multithreaded environment, the apartment threading model used by ArcObjects, Threads in Isolation, must be considered. This model works by eliminating cross-thread communication. All ArcObjects references within a thread should only communicate with objects in the same thread...

...For this model to work, the singleton objects at ArcGIS 9.x were designed to be singletons per thread and not singletons per process. The resource overhead of hosting multiple singletons in a process is outweighed by the performance gain of stopping the cross-thread communication that would occur if the singleton were created in one thread, then accessed from the other threads...

Activator class to create singletons avoids problem: ... sometimes when you use the new keyword to instantiate a COM object, you are getting a reference to an object that exists. This happens when attempting to instantiate a singleton class that has previously been instantiated. The .NET Framework is unable to wrap in a strongly typed RCW an instance of an object that has previously been wrapped in the generic System.__ComObject RCW ...

-

I have been in the same issue, but my environment came from versions 9.2, 9.3, and the application was migrated to version 10.

The solution that was to register the assembly using the REGASM.exe tool. Registering the assembly, does not produce the error.

-

I had this error occasionally when accessing IFeature or IRow objects which had been created with a recycling cursor. Holding a reference to those objects is discouraged and leads to serious problems, even though it works in most cases.

What are your threads doing on that feature class? Are they just reading data or are they modifying it? In the latter case you will run into problems because of race conditions. Deleting a row within one thread while cycling over it in another thread will probably not work.

Have you checked if the reference to your FeatureWorkspace is valid? Perhaps the reference has been released accidentally? How do you create the reference to your workspace? The correct (isolation mode) way to obtain a workspace object is to create a new WorkspaceFactory within each thread and then open a workspace with said factory. Although it also works if you pass the workspace reference to all threads but you buy that with some heavy marshalling/unmarshalling because of the inter-thread communication. Makes the code about 10-20% slower in my experience.

edit:

This code runs perfectly with ArcGIS 9.3.1. It creates 10 threads which access in parallel the same Workspace and open a feature class to read from it. Maybe you have some connection limits to your Sde-Workspace?

    private void Click()
{
for(int i=0; i<10; i++)
{
t.SetApartmentState(ApartmentState.STA);
t.Name = "worker" + i;
t.Start();
}

t.Interrupt();
}
}

private void Run()
{
IWorkspaceFactory fac = new AccessWorkspaceFactoryClass();
IWorkspace ws = fac.OpenFromFile(@"g:\path\to\my.mdb", 0);
IFeatureWorkspace fws = ws as IFeatureWorkspace;

try {

ITable table = fws.OpenTable("featureClassName");
ICursor cursor = table.Search(null, true);
IRow row = cursor.NextRow();
while(row != null) {
// do something time consuming
row.Fields.FindField("AttrName");
row = cursor.NextRow();
}
Marshal.ReleaseComObject(cursor);
}

-
I have added some code which gets called on each thread. It breaks at opentable() method most of the time –  adhiman Oct 20 '10 at 12:53
I saw in your other thread that you do a Marshal.ReleaseComObject() on the feature class and the workspace. As to my knowledge this is NOT allowed and not necessary. Try removing these release statements. –  AndOne Oct 20 '10 at 13:21
that doesn't help much, I thought this may be a problem so I added these statements. –  adhiman Oct 21 '10 at 10:45
I added some code which works for me. If it doesn't work with your workspace then it's probably something SDE/database related. Meaning that there's too little information at the moment to solve your problem. –  AndOne Oct 21 '10 at 13:56

You probably have not marked the new threads as STA (Single Threaded Apartments).

I am sure you have read this document, so this isonly a reminder :)

If you are curious, the ArcObjects singletons have thread affinity (not process) and in their internal implementation will check for the threadid and keep a {threadid/singletoninstance} tuple in a global hash.

-