none
Need help with StringBuilder and thread synchronization RRS feed

  • Question

  • //Here is the code for the event handler that is initially translating the raw bytes to a string:  
     
    private void WinsockObjRef_OnDataArrival(object theEventRaiserObj, EventArgs_Winsock_DataArrival theEventArgsObj)  
    {  
        //String to hold the response after it is translated from a byte array to a string  
        string strResponse = null;  
     
        if (theEventArgsObj.ReceivedByteCount > 0)  
        {  
           if (theEventArgsObj.MessageBuffer[0] == 0)  
           {  
              //Message was received with a 4 byte start header (translate bytes taking the 4 byte start header into account)  
              strResponse = TWGlobals.ConvertByteArrayToString(theEventArgsObj.MessageBuffer, TWGlobals.HeaderBufferSize, theEventArgsObj.MessageBuffer.Length - TWGlobals.HeaderBufferSize);  
           }  
           else  
           {  
              //A message fragment has been received (no 4 byte start header -- translate all recieved data)  
              strResponse = TWGlobals.ConvertByteArrayToString(theEventArgsObj.MessageBuffer, 0, theEventArgsObj.MessageBuffer.Length);  
            }  
       }  
                
       //Trim the response and append to global StringBuilder object        
       MessageBuilder.Append(strResponse.Trim(TWGlobals.InvalidMessageContent));  
                  
       //Call parsing function  
       Parse(theEventArgsObj);  
    }  
     
    //Here is the code that is parsing the data after it is appended to the StringBuilder:  
    private void Parse(EventArgs_Winsock_DataArrival theEventArgsObj)  
    {  
        string strMessage = null;  
        int intStartPos = 0;  
        int intEndPos = 0;  
     
        while (true)  
        {  
           //Find the string that denotes the start of the message (SOH)  
           intStartPos = MessageBuilder.ToString().IndexOf(StartHeader, intEndPos);  
                      
           //If it does not exist remove all data from StringBuilder and exit loop  
           if (intStartPos == TWGlobals.InvalidStringSearchHandle)  
           {  
              MessageBuilder.Remove(0, MessageBuilder.Length);  
     
              break;  
           }  
                      
           //Find the string that denotes the end of a complete message (EOM)  
           intEndPos = MessageBuilder.ToString().IndexOf(EndHeader, intStartPos);  
     
           //If it does not exist then remove everything up to the StartHeader (SOH) and exit the loop until more data is received  
           if (intEndPos == TWGlobals.InvalidStringSearchHandle)  
           {  
              MessageBuilder.Remove(0, intStartPos);  
     
              break;  
           }  
                      
           //Add the length of the End of Message string (EOM) to the end position  
           intEndPos += EndHeader.Length;  
                      
           //Extract a complete message from the StringBuilder  
           strMessage = MessageBuilder.ToString().Substring(intStartPos, (intEndPos - intStartPos));  
     
           //Set the start position equal to the end of the extracted message  
           intStartPos = intEndPos;  
                      
           //Raise the extracted string up in an event  
           EventEntry_ResponseReceived(new EventArgs_TWmdsMessageRouter_ResponseReceived(strMessage, strMessage.Length, theEventArgsObj.TWConnectionObjRef, theEventArgsObj.UserEventMessage));  
        }  

    I have a class that is receiving data asynchonously from a server and then raises that data up in an event to another class that then parses the data received. Because there are times where a message can be fragmented, I am storing the data once it is translated (from a byte array to a string) in a StringBuilder object. In my event handler, after the bytes are translated into a string and stored in this StringBuilder object, I am then parsing the data out of the StringBuilder object by searching for the message start header (SOH) and the message end header (EOM). After I extract the complete message, I set the start position offset to the location in the StringBuilder to the position where the extracted message ended and then I continue searching for complete messages to extract. If a message has a start header (SOH) and no end header (EOM), then the new data received is appended into the StringBuilder until a complete message (a string that contains a SOH and EOM tag) is found. Once that complete message is extracted it is in turn raised up in an event to another object -- so on and so forth until it reaches the GUI application that writes the complete amount of data to a file.

    The problem I am encountering is that each time I run the code, the data being written to the file is inconsistent. Sometimes I get the right amount of data, sometimes I get duplicates and sometimes I get nothing. I don't know if this is a thread synchronization issue (since the Socket code that is initially getting the raw bytes is running asynchronously in its own threadpool) or some other kind of issue. I am not even sure where the problem is occuring. If I step through the code, I get the proper amount of data. If I put a Debug.Print statement in there, the data is fine. However, if I don't include anything then the data, once it is written to the file contains many duplicates.

    Can someone please take a look at my code and see if there is something wrong?

    Thursday, January 15, 2009 6:40 PM

Answers

  • What exactly is your protocol?

    One thing that sticks out to me as "probably wrong" is the 4-byte start header detection, but I can't say for sure without knowing the details of the protocol you're using.

    I don't think there's anything wrong with your StringBuilder usage as regarding threads; I'm assuming that both the functions you posted run in a ThreadPool thread context. Just remember that EventEntry_ResponseReceived will also be run in a ThreadPool context.

           -Steve

    • Marked as answer by Zhi-Xin Ye Wednesday, January 21, 2009 11:41 AM
    Friday, January 16, 2009 3:28 AM