[GIS] Multithreading with ArcObjects

arcobjects

I am getting some weird errors while trying to implement multithreading with ArcObjects.
I am trying following things on per thread basis:

1) Open SDE Workspace
2) Open Feature class
3) Perform Icursor

Eventually, It fails with some errors like:
"Memory could not be read or write" or "AccessViolationException".
Looks like there are some memory leaks (though I don't know exactly where).

For more details please refer to the code below:

foreach (string featureClassName in settings.FeatureClassNames)  
{  
            Thread thread = new Thread(new ParameterizedThreadStart(ReadFeatureClass));  
            thread.ApartmentState = ApartmentState.STA;  
            object[] parameters = CreateParameters(featureClassName);  
            thread.Start(parameters);  
}  
    private void ReadFeatureClass(object parameters)  
    {  
        Settings settings;  
        string featureClassName;  
        ExtractParameters(parameters as object[], out settings, out featureClassName); 
        IFeatureWorkspace featureWorkspace = OpenFeatureWorkspace(settings); 
        ITable featureClass = featureWorkspace.OpenTable(featureClassName);  
        Marshal.ReleaseComObject(featureClass);  
        Marshal.ReleaseComObject(featureWorkspace);          
      }    

    private IFeatureWorkspace OpenFeatureWorkspace(Settings settings)  
    {  
        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("PASSWORD", settings.Password);  
        connectionProperties.SetProperty("VERSION", settings.Version);  

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

Best Answer

As I look at it, without the benefit of what you're looking for with the ICursor, I don't know that you need to fire this off into a new thread. I've used SDE Connections like yours many times. Below is an example from my code base that is currently working (I have an issue when I attempt to CREATE a feature class against a FGDB, but my sde is connecting great)

    public IWorkspace OpenSDEWorkspace(String server, String instance, String database,
        String version, String user, String password)
    {
        try
        {
            //create and populate the property set.
            IPropertySet2 propertySet = new PropertySetClass();
            propertySet.SetProperty("SERVER", server);
            propertySet.SetProperty("INSTANCE", instance);
            propertySet.SetProperty("DATABASE", database);
            propertySet.SetProperty("USER", user);
            propertySet.SetProperty("PASSWORD", password);
            propertySet.SetProperty("VERSION", version);
            IWorkspaceFactory2 sdeWorkspaceFactory;
            sdeWorkspaceFactory = (IWorkspaceFactory2)new SdeWorkspaceFactoryClass();
            IWorkspace workspace = (IWorkspace)sdeWorkspaceFactory.Open(propertySet, 0);

            return workspace;
        }
        catch (Exception e)
        {
            throw new Exception(String.Format("arcSDEWorkspaceOpen: {0}", e.Message), e);
        }
    }

    public ArrayList GetDomainValues(String codedvaluedomain)
    {
        ArrayList arrayList = new ArrayList();
        IWorkspace ws = (IWorkspace)ArcMap.Editor.EditWorkspace;
        if(ws == null)
        {
            ws = OpenSDEWorkspace("ip", "5151", "database", "version", "user", "password");
        }
        IWorkspaceDomains domains = (IWorkspaceDomains)ws;
        object[] domainobject = null;


            IEnumDomain domainEnum = domains.Domains;
            IDomain domain = domainEnum.Next();
            String name = "";

            while (domain != null)
            {
                name = domain.Name;
                domain = domainEnum.Next();
                if (name.Equals(codedvaluedomain))
                { 
                    break;
                }
            }
            ICodedValueDomain codeddomain = new CodedValueDomainClass();
            codeddomain = domains.get_DomainByName(name) as ICodedValueDomain;
            domainobject = new object[codeddomain.CodeCount];

            for (int a = 0; a < codeddomain.CodeCount; a++)
            {
                object domainvalue = codeddomain.get_Value(a);
                String domainvaluename = codeddomain.get_Name(a);
               arrayList.Add(domainvaluename);

            }

        return arrayList;
    }

give your code a run without the thread and let it all run on the main and let me know what happens.

Good luck

Luke

Related Question