Я пишу приложение с многоуровневым интерфейсом связи.
Это было сделано, чтобы абстрагировать связь от части пользовательского интерфейса приложения и также сделать это более масштабируемым/удобным в сопровождении.
Например:
Рассмотрите каждое поле в числе выше как отдельный класс.
Универсальный Интерфейс Comms заполняет строковые переменные, описывающие проведенные данные и comms "здоровье", которые в свою очередь копируются до Приложения через серию вызовов государственной функции. Например, Приложение позвонило бы 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
заполняется асинхронно другими функциями в классе.
Я живо состояние состязания происхожу между string sRetVal = this.sText;
и следующая строка this.sText = null;
.
Кто-то может предложить способ избежать или предотвратить это состояние состязания? Был бы с помощью StringBuilder
справка, или там иначе, что я должен делать это?
Вероятно, вы должны получить блокировку каждый раз, когда захотите коснуться this.sText
- в функциях, которые его обновляют, а также в вашем GetText
функция. Это гарантирует, что только один поток за раз возится с ним, поскольку (при условии, что ваш поток имеет блокировку) другие потоки будут сидеть и ждать, пока текущий поток не будет завершен.
Я бы порекомендовал вам использовать StringBuilder, отчасти для упрощения блокировки, поскольку блокировка строки, которая оказалась интернированной или отключенной в середине заблокированной операции (и, таким образом, разблокированной с точки зрения постороннего), может вызвать очень плохое моджо. Что-то вроде этого может помочь:
lock (this.sbText)
{
sRetVal = this.sbText.ToString();
this.sbText.Length = 0;
}
В качестве альтернативы вы можете заблокировать этот
, но это некрасиво - ваши блокировки должны быть внутри, как можно более приватными, чтобы избежать странных побочных эффектов (например, если некоторые другой объект пытался получить блокировку этого объекта - он не мог этого сделать, пока sbText
изменялся).
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;
}
}
в вашем наборе
lock( someObject )
{
//...
this.sText = value;
}
Этот код наверняка не будет работать в многопоточной среде, поскольку вы не защищаете sText. Вам нужно заблокировать всех, кто имеет к нему доступ.