This project has moved. For the latest updates, please go here.

Is FrameParser thread safe?

Nov 16, 2011 at 10:42 PM

Hello Ritchie:

I want to confirm whether the FrameParser, no matter what protocol it deals with, is thread safe.

For example, if there are multiple InputAdapters share the same C37.118 FrameParser, and I set that parser's ExecuteParseOnSeparateThread to be false, then will it cause race condition when each InputAdapter writes into that FrameParser from its own thread?

I know most of the parsing algorithm are implemented in "TVA.Parsing.BinaryImageParserBase", and I don't see any synchronization in that class. I just guess, if I use the default value of ExecuteParseOnSeparateThread (which is false), then the FrameParser is not thread-safe.

Then another question comes. In PMU Connection Tester, it is very common that the ConfigurationFrame is sent through TCP, while the DataFrame is sent through UDP. they definitely come from two different IO threads. so is there any chance that it will cause race and corrupt the parsing process?

Thank you very much.

Nov 21, 2011 at 8:09 PM
Edited Nov 21, 2011 at 8:11 PM

The MultiProtocolFrameParser creates an individual parser for each socket connection that imposes a parser per thread restriction for safety - so using this class is the recommended way of parsing phasor data.

Otherwise you can use a single frame parser directly, but you should only feed it data from a single connection. Using a single parser for multiple streams of data would likely cause issues - not only because of multi-threading issues - but because most phasor protocols, by design, do not support interleaved data.

 In cases where you have a command channel and a data channel you send data on the TCP command channel, but the configuration frame typically returns on the UDP data channel (at least in my experience). If it if did not, it could pose an issue, but the likely scenario would be that the parser would simply fail to parse the requested command frame due to data from TCP command channel being interleaved with data being received from UDP data channel.

Also, the execute parse on a separate thread feature basically moves the data parsing onto a thread other than the communications thread - this rarely used option allows the system to dedicate a thread to parsing. It was though that if the data frames ever got big enough, you might need to separate the socket data collection from the parsing to make sure the system could stay ahead of the load, but we've never encountered this to date.

Note that we've not encountered any issues here - but if you find something that you recommend correcting, just let us know!


Nov 22, 2011 at 12:03 AM
Edited Nov 22, 2011 at 12:08 AM

Hello Ritchie:

I really appreciate your explanation and great help. However, I have viewed the source codes of MultiProtocolFrameParser another time, and I found it doesn't work as you described. Please point me out if I have some misunderstandings. Below description are based on openPDC 1.4 SP1.

Take PmuConnectionTester for an example. if the PmuConnectionTester wants to connect a device with UDP data channel and TCP command channel. after you click the "connect" button, MultiProtocolFrameParser.Start() will be invoked.

in Start() method, it calls InitializeCommandChannel. in this method, it sets "m_commandChannel.ReceiveDataHandler = Write", and then send a DeviceCommand.SendConfigurationFrame2 command to the device. so the configuration frame will come from that TCP socket, and the binary image of that configuration frame will be passed into Write function.

after that, InitializeDataChannel is invoked. in this function, and in this case, it will initialize a UdpClient, and set "m_dataChannel.ReceiveDataHandler = Write", THE SAME WRITE. then data frame will come from that UDP socket, and its binary image will be passed into Write function.

then we go to "Write" function, we can see that "m_frameParser.Write(buffer, offset, count)", A SINGLE, SHARED FrameParser is used to deal with binary image received from different IO threads (one for TCP, another for UDP).

so in this case, it is not working as you have claimed, "The MultiProtocolFrameParser creates an individual parser for each socket connection". but, that UDP socket for data, and TCP socket for configuration, share the same FrameParser. That is definitely a risk for concurrency issue, and interleaved data will corrupt the parsing process.

I am not surprised to hear that you never encounter any "concurrency and interleaved" issue, because in our application, I have a similar components, which also share a single FrameParser among multiple InputAdapters, and that component never has any problems by now either. But in my opinion, that is only because I am just lucky enough, and I decide to correct that component in the next version.

Please point me out if there is any mechanism in the codes which solves this concurrency issue elegantly, but is just ignored by me when I reviewed the codes.

Thank you very much.

Nov 22, 2011 at 12:58 PM

That's correct - if data did come through from both sockets it could cause an issue. However, in practice, all data is returned on the UDP channel when both a TCP command channel and a UDP data channel is defined. Note that the write method is subscribed for the TCP channel and is used when a TCP only socket is established.

We should likely adding some locking "in case" data did arrive from both channels simultaneously - at least for saftey.


Nov 22, 2011 at 5:07 PM

thanks for your explanation, Ritchie.

but I am still a little bit confused. In the case that a device has UDP data channel and TCP command channel, binary data DID come through different sockets. it is NOT as you said that, "all data is returned on UDP channel". only DataFrame is returned through UDP channel, and ConfigurationFrame is returned through TCP channel.

for example, in the sample case, that device is a "TVA.PhasorProtocols.IeeeC37_118.Concentrator", and that class most of the time uses its member field "private TcpServer m_commandChannel;" as its command channel. and in the method "TVA.PhasorProtocols.IeeeC37_118.Concentrator.DeviceCommandHandler", it calls "commandChannel.SendToAsync(clientID, m_configurationFrame.BinaryImage);", then the ConfigurationFrame definitely is returned through TCP channel, how can it be returned through UDP?

and in "TVA.PhasorProtocols.MultiProtocolFrameParser.Start()", it nearly calls "m_commandChannel.ConnectAsync();" and "m_dataChannel.ConnectAsync();" at the same time. Since both operations are asynchronous, then the order of receiving DataFrame or ConfigurationFrame cannot be guaranteed, and there is risk for concurrency and interleaved data.

In my opinion, adding lock is not a good solution to this problem (at least for PmuConnectionTester), because the race condition occur only once when the ConfigurationFrame is returned, and the FrameParser is need to be written so frequently. so Locking is just a too-heavy solution, and I think a better solution is to define explicitly the order for receiving ConfigurationFrame and DataFrame.

for example, if the user of PmuConnectionTester choose to load ConfigurationFrame from a existing file, and it won't send command to ask for ConfigurationFrame. and if the user choose to request the ConfigurationFrame online, then it first send command to request ConfiguratonFrame, and it only start receiving DataFrame AFTER the ConfigurationFrame is received. Then there is no chance for concurrency and interleaved data, so no lock is needed at all.

above is just my opinion. Hopefully, it can provide little help.

thanks a lot.

Nov 22, 2011 at 5:52 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.