Link to home
Start Free TrialLog in
Avatar of gvector1
gvector1

asked on

Protected Memory Exception

I have an application that is giving me the following exception :
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

I think it has something to do with the fact that I am making calls to unmanaged code through interop.  I never had this problem until I started doing the interops through background workers.  I am trying to transverse a directories and files and read one type of file in order to load it into a table in a mysql database.  These files I am trying to read and load into the table are of a custom file type.  It takes the code written in C++ to open and read the files, therefore I have to make the calls through interop.  Because there are so many directories I start off 30 Background workers and continuously start each one with a directory to process.  So I know there are constant hits to the interop and dll that the interop is accessing.  Here is my code...

Here is the method that keeps crashing with the exception:
private DataTable SpreadtoTable()
            {
            int ptr = -1;
            try
            {
                int lrc, lrr;
                int[] cols, wids;
                StringBuilder line = new StringBuilder(81);
                StringBuilder lineatt = new StringBuilder(128);

                DataTable dtSpread = new DataTable();

                ptr = SpreadClass.read_spread(mPath);
                if (ptr == 0 || ptr == -1)
                    return null;

                lrr = SpreadClass.get_LRR(ptr);
                lrc = SpreadClass.get_LRC(ptr);
                cols = new int[lrc];
                wids = new int[lrc];

                SpreadClass.get_col_indexs(ptr, cols, wids);

                for (int k = 1; k <= lrc; k++)
                {
                    SpreadClass.get_column_attr(ptr, "Column Name", cols[k - 1], line, lineatt);
                    if (line.ToString().ToUpper() == "DATE")
                        dtSpread.Columns.Add(line.ToString(), Type.GetType("System.DateTime"));
                    else
                        dtSpread.Columns.Add(line.ToString());
                }

                for (int i = 1; i <= lrr; i++)
                {
                    DataRow dr = dtSpread.NewRow();

                    for (int j = 1; j <= lrc; j++)
                    {
                        SpreadClass.getraw(ptr, i, cols[j - 1], line, lineatt);
                        dr[j - 1] = line.ToString();
                    }

                    dtSpread.Rows.Add(dr);
                }
                SpreadClass.deletedb(ptr);
                return dtSpread;
            }
            catch (Exception ex)
            {
                StreamWriter sw = new StreamWriter(spreadLog, true);
                FileInfo fi = new FileInfo(mPath);
                sw.WriteLine(ex.Message + " = " + fi.DirectoryName + " - Unable to convert Master.Cat to table");
                sw.Close();
                return null;
            }
            finally
            {
                SpreadClass.deletedb(ptr);
            }
}

Here are my DllImports:
            [DllImport("spread.dll")]
            public static extern int read_spread(string      fname);

            [DllImport("spread.dll")]
            public static extern void getraw(int ptr, int row, int col,
                  [MarshalAs(UnmanagedType.LPStr)]StringBuilder str,
                  [MarshalAs(UnmanagedType.LPStr)]StringBuilder stratt);

            [DllImport("spread.dll")]
            public static extern int get_LRC(int file);

            [DllImport("spread.dll")]
            public static extern int get_LRR(int file);

            [DllImport("spread.dll")]
            public static extern void get_column_attr(int ptr, string headatt,
                  int column,
                  [MarshalAs(UnmanagedType.LPStr)]StringBuilder str,
                  [MarshalAs(UnmanagedType.LPStr)]StringBuilder stratt);


Here is the C Code            
/****************************************************************************/
long int read_spread ( fname )
char             *fname;
{
}

/****************************************************************************/
getraw ( dbptr, row, col, str, stratt )
long int    dbptr;
int         row;
int         col;
char        *str;
char        *stratt;
{
}

/****************************************************************************/
get_LRC(fileptr)
long int fileptr;
{
}

/****************************************************************************/
get_LRR(fileptr)
long int fileptr;
{
}

/****************************************************************************/
get_column_attr ( dbptr, colatt, col, str, stratt )
long int    dbptr;
char        *colatt;
int         col;
char        *str;
char        *stratt;
{
}

I know that this is a lot to read and look at, but any advice will be greatly appreciated....

Thanks,
Kendal

Avatar of AlexFM
AlexFM

Can you show exactly what C# line gives exception?
Avatar of gvector1

ASKER

It is the SpreadClass.deletedb(ptr).  This is where the memory is where the pointer to the file is disposed of and the memory released.  It has always worked fine until now.  I was kind of thinking that it may have something to do with my threading.  What do you think?????
SpreadClass.deletedb(ptr);

This line is executed twice - in try block and in finally block. Remove it from try block.
If this doesn't help, post enough information to understand what happens: you the code you posted it is impossinle to see what happens in deletedb function, how unmanaged functions are called.
Could it be possible that the dll that I am using Interop calls to is not thread safe.  Is it possible that that could have any bearing on this.  I took the first deletedb statement out, but the problem still occurs.  I am thinking that if the dll is not thread safe, when multiple threads are making calls at the same time to the dll that this type of problem can occur.  Is this possible??????
Yes, this is possible. To test this run the same code in one thread and see whether it happens.
I origionally did this in one thread.  Never had this problem...but it was taking too long.  This application has to transverse hundreds of thousands of directories and parse one specific file in each directory to load it into a database.  Now here is another question.  How can I create a lock that will work across threads.  Basically so when one thread goes to access the dll method call it will lock until it is done and any other subsequent calls will be blocked until the first call is complete.  It that an acceptable workaround and how would it ideally be done?????
You can create static object for synchronization:

static object syncObject = new Object();

Make every call to unmanaged library by the following way:

lock(syncObject)
{
    // unmanaged call
}

Using static synchronization object serializes all calls inside of lock{} block in the whole program.
I don't understand completely your code. Possibly it is enough to protect resources only for every class instance. In this case use non-static synchronization object:
object syncObject = new Object();

Try both versions. First gives better protection, but it is slower. I don't know exactly reading your code, whether you need first or second version.
My application starts and I start about 30 background workers which work through directories opening specific files that require the dll to read.  Each bg worker opens the file and loads the contents into a database table.  
The criteria is what kind of resources are accessed by function, or unmanaged function. If these resources belong to class instance, it is enough to use protection on instance level. If this is global resource, protection should be done on global (static) level.
These resources are accessed at an instance level.  Each Background Worker creates an instance of a class that accesses the resource.  So am I correct in saying that if the instance of the class creates a lock on the object, another background worker will not be able to create a lock and access the resource????
ASKER CERTIFIED SOLUTION
Avatar of AlexFM
AlexFM

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks AlexFM,
That lock code helped me out greatly.