Reputation: 14254
I'm writing an application with a layered communications interface.
This was done to abstract the communications from the user-interface part of the application and also to make it more scaleable/maintainable.
For instance:
Consider each box in the figure above as a separate class.
The Generic Comms Interface populates string variables describing the transacted data and comms "health," which are in turn copied up to the Application through a series of public function calls. For example, the Application would make a call to the App-Sub-System:
class Application
{
private void SomeUpdateFunction()
{
this.textBox1.AppendText(this.AppSubSystem.GetText());
}
}
class AppSubSystem
{
public string GetText()
{
return this.GenericCommsInterface.GetText();
}
}
class GenericCommsInterface
{
public string GetText()
{
string sRetVal = this.sText; // sText is populated by other functions in the class.
this.sText = null; // Suspected race condition is here.
return sRetVal;
}
}
sText
is populated asynchronously by other functions in the class.
I belive a race condition is happening between string sRetVal = this.sText;
and the following line this.sText = null;
.
Can someone suggest a way to avoid or prevent this race condition? Would using StringBuilder
help, or is there another way that I should be doing this?
Upvotes: 8
Views: 6437
Reputation: 10758
public string GetText()
{
lock( someObject )
{
string sRetVal = this.sText; // sText is populated by other functions in the class.
this.sText = null; // Suspected race condition is here.
return sRetVal;
}
}
in your set
lock( someObject )
{
//...
this.sText = value;
}
Upvotes: 0
Reputation: 86534
You should probably be acquiring a lock any time you want to touch this.sText
-- in the functions that update it, as well as your GetText
function. This would ensure that only one thread at a time is messing with it, as (assuming your thread has the lock) other threads will sit and wait til the current thread is done.
I'd recommend you use a StringBuilder, partly to simplify locking, as locking a string that happened to be interned, or one switched out in the middle of the locked operation (and thus unlocked, from an outsider's perspective) could cause real bad mojo. Something like this would help:
lock (this.sbText)
{
sRetVal = this.sbText.ToString();
this.sbText.Length = 0;
}
Alternatively, you could lock on this
, but that's ugly -- your locks should be inside, as private as possible, in order to avoid weird side effects (like if some other object were trying to acquire a lock on this object -- it couldn't do so while sbText
was being altered).
Upvotes: 5
Reputation: 9093
This code most certainly won't work in a threaded environment as you aren't protecting sText. You need to lock everybody that accesses it.
Upvotes: 1