Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

This is a problem I have been struggling with for awhile. The code below takes 1-3 input feature layers (pFLayer) that were stored into a list called pFeatureLayerCollection, casts them into IGeoDatasets and executes EucDistanceFull in parallel to get distance rasters from them. The output IGeoDatasets are added to a list. After the Parallel.ForEach ends, if there is more than 1 output raster, I attempt to get the localminimum of the rasters using the method below. It runs fine if I give it one input raster. It also runs fine if I run it with multiple rasters sequentially (not in parallel) However, if I try to execute it with more than one raster in parallel, it fails with this error every time: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. (Esri.ArcGIS.SpatialAnalyst at ESRI.ArcGIS.SpatialAnalyst.RasterLocalOpClass.LocalStatistics(IGeoDataset LocalData, esriGeoAnalysisStatisticsEnum Type)

             ESRI.ArcGIS.Geometry.IEnvelope pExt; //create a new envelope to hold the feature class' size information
            pExt = new EnvelopeClass(); //instantiate the envelope as an object
            pExt.XMin = **[Some given known double value]**;
            pExt.YMin = **[Some given known double value]**;
            pExt.XMax = **[Some given known double value]**;
            pExt.YMax = **[Some given known double value]**;

            string StrOutRasPath = **[Some given valid filepath]**;

            List<IGeoDataset> pMinimumGeodatasetCollection = new List<IGeoDataset>(); //store output distance rasters


            Parallel.ForEach(pFeatureLayerCollection, pFLayer =>
            {
                ESRI.ArcGIS.DataSourcesRaster.IRasterWorkspace pTempRWS;
                ESRI.ArcGIS.Geodatabase.IGeoDataset pOutputRaster = null;
                ESRI.ArcGIS.GeoAnalyst.IRasterAnalysisEnvironment pEnv = null; //Create a raster analysis environment. This sets up an area to do raster operations in
                ESRI.ArcGIS.SpatialAnalyst.IDistanceOp pDistanceOP; //Create raster DistanceOp object
                pDistanceOP = new RasterDistanceOpClass(); //define the newly created object as a new raster distance operation object

                string g_tempFolder = null;
                lock (strOutRasPath) //threadsafe creation of folders from method
                {
                    g_tempFolder = CreateTempFolder(strOutRasPath);
                }


                lock (pWSF)
                {
                    pTempRWS = (IRasterWorkspace)pWSF.OpenFromFile(g_tempFolder, 0);
                }




                ESRI.ArcGIS.Geodatabase.IWorkspaceFactory pWSFact; //create general workspace factory (this is the directory you will be working in)
                //pWSFact = new ShapefileWorkspaceFactoryClass(); //set general workspace as a shapefile workspace. WARNING: USING THIS CAUSES A STRANGE COM REWRAPPING ERROR. IT IS AN ESRI BUG

                Type t = Type.GetTypeFromProgID("esriDataSourcesFile.ShapefileWorkspaceFactory"); //DO NOT REMOVE THIS LINE OR THE FOLLOWING TWO LINES. Fixes strange casting error from COM rewrapping. (ESRI BUGFIX)
                System.Object obj2 = Activator.CreateInstance(t);

                pWSFact = (ShapefileWorkspaceFactory)obj2;

                ESRI.ArcGIS.Geodatabase.IFeatureWorkspace pFeatureWorkspace; //create a feature workspace to handle features
                pFeatureWorkspace = (IFeatureWorkspace)pWSFact.OpenFromFile(g_tempFolder, 0); //set feature workspace as the shapefile workspace defined earlier, and specify a file location



                ESRI.ArcGIS.Geodatabase.IGeoDataset pTempMinRaster;             
                ESRI.ArcGIS.Geodatabase.IGeoDataset pTempGeodataset;
                ESRI.ArcGIS.Carto.IFeatureLayer pTempFeatureLayer;

                ////////////
                //Loop through all features.
                ////////////

                ESRI.ArcGIS.GeoAnalyst.IConversionOp pConvOp;
                pConvOp = new RasterConversionOpClass();

                ESRI.ArcGIS.Carto.IFeatureSelection pFeatureSelection;
                pFeatureSelection = (IFeatureSelection)pFLayer; // ***IMPORTANT*** THIS SETS THE CURRENT FEATURE LAYER IN COMBOBOX TO THE FEATURE SELECTION TO BE USED FOR CONVERSION TO RASTER 
                ESRI.ArcGIS.Geodatabase.ISelectionSet pSelectionSet;
                pSelectionSet = pFeatureSelection.SelectionSet; //Defines a selection set of features. The pFeatureLayer information is stored here.

                ESRI.ArcGIS.Geodatabase.IFeatureCursor pFCursor2;
                ESRI.ArcGIS.Geodatabase.IFeature pFeature2;
                ESRI.ArcGIS.Geodatabase.IQueryFilter pQueryFilter;

                pQueryFilter = new QueryFilterClass();
                pFCursor2 = pFLayer.Search(null, false);
                pSelectionSet = pFeatureSelection.SelectionSet;
                pFeature2 = pFCursor2.NextFeature();

                pEnv = (IRasterAnalysisEnvironment)pDistanceOP;
                pEnv.OutWorkspace = (IWorkspace)pTempRWS;
                pEnv.SetCellSize(esriRasterEnvSettingEnum.esriRasterEnvValue, cellsize);

                lock (pExt) //threadsafe grab of pExt from outside Parallel.Foreach
                {
                    pEnv.SetExtent(esriRasterEnvSettingEnum.esriRasterEnvValue, pExt);
                }



                    ESRI.ArcGIS.Geodatabase.IGeoDataset temporaryGeodataset = (IGeoDataset)pFLayer.FeatureClass;

                    pOutputRaster = pDistanceOP.EucDistanceFull(temporaryGeodataset, true, false, false);



                lock (pMinimumGeodatasetCollection) //threadsafe adding to the list of output geodatasets
                {
                    pMinimumGeodatasetCollection.Add(pOutputRaster);
                }

                pFeatureSelection.Clear();

            });

            //LIST CREATION COMPLETE. NOW IF TWO OR MORE RASTERS WERE CREATED, GET THE MINIMUM USING LOCALMINIMUM METHOD

            if (pMinimumGeodatasetCollection.Count == 1) //if just one input feature class
            {
                pMinimumRaster = pMinimumGeodatasetCollection[0];
                pFeatureLayer = pFeatureLayerCollection[0];

            }

            else if (pMinimumGeodatasetCollection.Count == 2) //if two input feature classes, get local minimum
            {

                pMinimumRaster = LocalMinimum2Rasters(pMinimumGeodatasetCollection[0], pMinimumGeodatasetCollection[1], strOutRasPath + "\\tmpVoro0004");

            }

There is the bulk of the code, and below is the implemented LocalMinimum method. LocalMinimum3Rasters does the exact same as LocalMinimum2Rasters, but acommodates for one more raster. The final line of this code is where the program is failing.

    public IGeoDataset LocalMinimum3Rasters(IGeoDataset pRaster1, IGeoDataset pRaster2, IGeoDataset pRaster3, string strOutPath)
    {

        ESRI.ArcGIS.DataSourcesRaster.IRasterBandCollection pRBCollTmp;
        ESRI.ArcGIS.DataSourcesRaster.IRasterBand pRBand;

        ESRI.ArcGIS.DataSourcesRaster.IRasterBandCollection pRBColl;
        pRBColl = new RasterClass();
        pRBCollTmp = (IRasterBandCollection)pRaster1;
        pRBand = pRBCollTmp.Item(0);
        pRBColl.AppendBand(pRBand);
        pRBCollTmp = (IRasterBandCollection)pRaster2;
        pRBand = pRBCollTmp.Item(0);
        pRBColl.AppendBand(pRBand);
        pRBCollTmp = (IRasterBandCollection)pRaster3;
        pRBand = pRBCollTmp.Item(0);
        pRBColl.AppendBand(pRBand);

        //Create a RasterLocalOp operator
        ESRI.ArcGIS.SpatialAnalyst.ILocalOp pLocalOp = new RasterLocalOpClass();

        ESRI.ArcGIS.Geodatabase.IWorkspace pWs;
        ESRI.ArcGIS.Geodatabase.IWorkspaceFactory pWSF = new RasterWorkspaceFactoryClass();
        pWs = pWSF.OpenFromFile(strOutPath, 0);

        return pLocalOp.LocalStatistics((IGeoDataset)pRBColl, esriGeoAnalysisStatisticsEnum.esriGeoAnalysisStatsMinimum);

    }

What could be causing this error? It seems to be directly tied to parallelism - I've noted that all operations work perfectly fine if I use a regular foreach instead of Parallel.ForEach.

Extra information: The program creates the two distance rasters every time - If I go to the temporary folders I created in this code after the program crashes, I will find the two temporary rasters wholly intact and perfectly created.

share|improve this question
add comment

2 Answers 2

up vote 2 down vote accepted

I'd instantiate your raster workspace factory like you did with the shapefile workspace in the main loop this since it is also a singleton object:

//Create RasterWorkSpaceFactory
Type factoryType = Type.GetTypeFromProgID(
                "esriDataSourcesRaster.RasterWorkspaceFactory");
IWorkspaceFactory WSF = (IWorkspaceFactory)Activator.CreateInstance
                (factoryType);

It's also good practice to decrement the com objects while iterating. One place I see is with pFeature2. Before calling pFCursor2.NextFeature() on the cursor try calling:

System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeature2);

I'm not sure if these two tips will directly fix your problem but should help memory management in your program and increase stability. I most often see the error you describe when trying to re-use an object that another method has diposed of. I don't have time to wrap my mind around you program but think about which objects are being re-used.

share|improve this answer
    
Thanks for your answer. I'll give these a shot. –  Conor Jul 12 '13 at 18:36
    
Solved! Seems like the singleton object was the issue. I had several instantiations of RasterWorkspaceFactory strewn about my code that were instantiated using the "new" keyword. I got rid of all of these except for one instantiation and used CreateInstance instead of "new" and voila! My code now works without a crash. –  Conor Jul 22 '13 at 19:45
add comment

I think your objects are crossing thread boundaries, which is a big no-no in ArcObjects.

See this help topic for more information.

share|improve this answer
    
I think you're right. I will give this a read-through. –  Conor Jul 12 '13 at 18:53
    
The documentation you provided helped me get the answer. Thank you! –  Conor Jul 22 '13 at 19:47
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.