I have read multiple posts both on stack-overflow and elsewhere that StringBuilder is not Thread safe and when accessed (read / written to) from multiple threads should be locked: here, here, here. I'm unclear about how to lock my Stringbuilder instances - in particular how many locks should be added and where.
I have the following code (snippet-ed):
class MemoryTracker
{
private Process extProc { get; set; }
private StringBuilder sb { get; set; }
internal int trackByIP(string ip)
{
...
...
sb = new StringBuilder();
extProc.OutputDataReceived += new DataReceivedEventHandler((s, e) => sb.Append(e.Data + "\n"));
extProc.ErrorDataReceived += new DataReceivedEventHandler((s, e) => sb.Append(e.Data + "\n"));
extProc.Start();
extProc.PriorityClass = ProcessPriorityClass.RealTime;
...
...
}
string getDataWStartEndPttrn(StringBuilder data, string strPttr, string endPttr, string extendedTerminator)
{
string s = data.ToString(); // <-- THROWS ArgumentOutOfRangeException
int si = getStartIdx(s, strPttr, patternDiff(strPttr, endPttr));
int se = getEndIdx(s, endPttr, patternDiff(endPttr, strPttr));
if (se >= 0 && si >= 0)
{
string s1 = s.Substring(si, se - si);
string sTMP = s.Substring(se);
string s2 = s.Substring(se, sTMP.IndexOf(extendedTerminator));
return s1 + s2;
}
return "";
}
Having placed the lock I still see the same error thrown.
class MemoryTracker
{
private Process extProc { get; set; }
private StringBuilder sb { get; set; }
private Object thisLock = new Object();
string getDataWStartEndPttrn(StringBuilder data, string strPttr, string endPttr, string extendedTerminator)
{
lock (thisLock)
{
string s = data.ToString() ; // <-- STILL THROWS ArgumentOutOfRangeException
}
...
...
QUESTION: How do I correctly think about where to place the lock / locks? There is no place where I explicitly create threads, so I assumed it would be a thread-safe usage of the StringBuilder.toString();
sb.Appendstatements.new DataReceivedEventHandler((s, e) => { lock (_sbLock) {sb.Append(e.Data + "\n"); }});, not like you are doing now.