Main Site Documentation

Odd behavior


#1

I have a method that seems to occasionally corrupt a value for no reason I can figure out. The method takes a variable length param list of arguments. The arguments are name/value pairs. I loop through the pairs and put the value in a tab separated StringBuilder based on the name. I calculate a lastValueIndex variable on entering the method and use that number as a conditional to stop looping. The method works fine for hundreds of calls but at about the same point in my program, the value of lastValueIndex seems to get corrupted and I get a ‘System.IndexOutOfRangeException’ error at

if ((int)values[valueNum] == columnNum)

When the exception happens, the debugger says there are 12 arguments in the values array being passed to the method. Executing values.Length in the watch window also give 12. Since the value of lastValueIndex is set to values.Lengh -1 when entering the method, it should have a value of 11 and I don’t re-assign lastValueIndex anywhere else. But the debugger says lastValueIndex = 17 which is definitely out of range.

Any ideas why this might be happening?

        private static bool foundColumn = false;

        private static int valueNum = 0;
        private static int columnNum = 0;
        private static int lastValueIndex = 0;

        public static void write(params object[] values)
        {
            lastValueIndex = values.Length - 1;
            sbWrite.Clear();

            valueNum = 0;
            lock (loggerLock)
            {
                while (valueNum < lastValueIndex)
                {
                    columnNum = 0;
                    foundColumn = false;
                    while (!foundColumn)
                    {
                        if ((int)values[valueNum] == columnNum)
                        {
                            //TODO need to do a better job formatting values to minimize length
                            if (columnNum == (int)ColumnNums.comment)
                            {
                                sbWrite.Append(values[valueNum + 1].ToString());
                            }
                            else
                            {
                                sbWrite.Append(((double)values[valueNum + 1]).ToString("f6"));
                            }
                            foundColumn = true;
                        }
                        else
                        {
                            columnNum = columnNum + 1;
                        }
                    }
                    sbWrite.Append(token);
                    valueNum = valueNum + 2;
                }
            }

            Debug.Print(sbWrite.ToString());
            sbWrite.AppendLine();
            Array.Clear(writeArray, 0, writeArray.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(sbWrite.ToString()), writeArray, sbWrite.Length);
            logFile.Write(writeArray, 0, Array.IndexOf(writeArray, 0));
            BTConsole.SendLine(sbWrite);
   
 }

#2

i have seen you look the loop
but the seting of the lastValueIndex is outside the look
an could be changed before the loop is ended.


#3

@ Gene - Since you are using a lock, we can assume that you are using threads. Without seeing the other code in your program, we can only guess what is happening. Guessing is not very productive.


#4

My guess is that the routine is being call while it is executing IE another thread is calling it while it is inside the loop. Doing so will change lastValueIndex before it finishes the loop.

Try moving the lock all the way to the top.


#5

A couple more facts.

  1. I only added the lock recently after the problem cropped up to see if it would help. I’ll try moving the lock to the top.

  2. I don’t explicitly run other threads but I’m pretty sure .net is. For example, I have a sensor interface running with a timer event handler that toggles several gpio lines with timed delays between level transitions. It doesn’t need to be very accurate so a timer seems to work fine. My understanding is.net will run that timer event handler in a separate thread. I’m guessing that may be my problem but still can’t understand why a variable that only gets assigned at the beginning of a method would have its value changed as a result of thread switching.

Thanks for the help.


#6

If a new thread calls this routine it will run up to the lock.


#7

Is there a special reason why you don’t use local variables inside the method, but class fields?
If you would do so, no other thread would be able to modify your variables.
The lock only helps if the code that modifies the fields also uses the lock.
Also since no NETMF internal thread knows anything about your fields, they can not change them.

If you need your variables last value available outside the method I would make local variables anyway and copy them to the static class fields before exiting the method.


#8

I don’t use local variables inside methods in an attempt to prevent Garbage Collection as much as possible. The lastValueIndex is declared private static inside my Logger class, it only gets used in the write method and nothing else in my program has a lastValueIndex variable.

This method only gets called from one other method in my main program. As far as I can tell, nothing else calls it. That’s kind of the reason I set up my program like this. I have several RS232 interfaces to instruments each with its own event handler. As soon as any event handler gets a complete message, it queues the message into a simple byte queue. There is one queue handler that dequeues messages and calls this write method as necessary. Nothing else should be calling this write method.

I’m still at a loss to understand how a variable declared private static inside a class can get modified under any circumstances by something outside the class. @ Reinhard - are you suggesting that if I declare a variable inside a method it is “better” protected from corruption than if I declare it private static outside a method? I can try that and see if it helps.

I do a lot of things to minimize GC mostly out of ignorance because I haven’t been able to find a detailed description of the way GC is implemented in .Net Micro. If someone knows of one, I’d love to see it.

I’m still working my way up the learning curve with .Net Micro and C# so all your comments and suggestions are a great help. Thanks again.


#9

A variable should keep it’s value if no one writes to it, no matter where it is declared.

I think in VS you can declare a breakpoint not only on code lines, but also when a variable value changes. I’m not 100% sure about this, nor if the NETMF debugger supports this.
But you could try it.


#10

@ Reinhard - I’ll see if I can set a breakpoint on a change in value. If not I’ll try checking for a change in value with an if statement and put a breakpoint there. Thanks for the suggestion


#11

Mystery solved, pilot error once again. I broke my own rule and was inadvertently calling the write method from some place other than where I should have been.

Thanks for all the help.