#c#
#c#
Вопрос:
У меня проблема с вызовом событий внутри блокировки.
Событие запускается внутри средства установки свойства в базовом классе (когда я изменяю значение свойства), и я вызываю это свойство в производном классе (внутри блокировки).
Код выглядит примерно так:
class BaseClass
{
public event EventHandler StatusChanged;
int _status = 0;
object lockA = new object();
public int Status
{
get
{
lock (lockA) { return _status; }
}
set
{
bool fireEvent = false;
lock (lockA)
{
if (_status != value)
{
_status = value;
fireEvent = true;
}
}
if (fireEvent)
StatusChanged(this, EventArgs.Empty);
}
}
}
class DerivedClass : BaseClass
{
object lockB = new object();
public void SetStatus(int newStatus)
{
lock (lockB)
{
this.Status = newStatus;
}
}
}
Свойство BaseClass вызывает событие вне блокировки, чтобы защитить себя от взаимоблокировок, но производный класс устанавливает новый статус внутри своей собственной блокировки.
Поскольку разработчик производного класса может не знать, как работает базовый класс, каков наилучший способ гарантировать, что взаимоблокировка не может произойти? Может быть, инициирование событий в асинхронном потоке?
Комментарии:
1. почему вы блокируете набор свойств в производном классе?
2. Мне нужно заблокировать код обновления, чтобы быть уверенным, что операция «проверка и обновление» является атомарной, иначе два разных потока могут изменить свойство одновременно. Та же проблема возникает, если один поток вызывает средство получения, в то время как второй поток вызывает средство установки для изменения статуса, средство получения может не возвращать правильное значение.
Ответ №1:
Блокировка в одном потоке не «блокируется», поэтому, на мой взгляд, в вашем коде нет риска взаимоблокировки.
Комментарии:
1. Да, но мы не знаем, что происходит в пользовательском коде, запущенном событием: возможно, он запускает другой поток и присоединяется () к нему, и этот поток снова вызывает метод setStatus(), вызывая взаимоблокировку
2. @usernnnn: Это был бы исключительно плохой дизайн, и я полностью согласен с тем, что фреймворк должен с радостью поддерживать взаимоблокировку, когда клиент нарушает потоковую обработку. [1.] никогда не выполняйте блокирующие операции внутри обработчика событий [2.] никогда не получайте доступ к службам / элементам пользовательского интерфейса из нескольких потоков, если это явно не предназначено для этой цели
3. Вы правы, я просто хотел найти какой-нибудь способ быть на 100% уверенным, что взаимоблокировки не может произойти, но я предполагаю, что это невозможно, когда вам приходится «зависеть» от какого-то неизвестного пользовательского кода..
4. @user728771 Ну да, возможно, проблема в конечном итоге в том, что свойство с блокировкой
Ответ №2:
Что ж, я думаю, мне придется согласиться, что там действительно нет риска взаимоблокировки. Но что вы думаете об использовании BeginInvoke() для запуска пользовательского кода?
BeginInvoke(this, EventArgs.Empty, null, null);
Комментарии:
1. Да, я также думал о том, чтобы вызвать событие в асинхронном потоке и покончить с этим..
Ответ №3:
Когда вы создаете базовый класс, просто прокомментируйте его как потокобезопасный, тогда, если какие-либо разработчики реализуют этот базовый класс и не видят, что в его комментариях указано, что он уже потокобезопасен, то это их собственная проблема.
Я думал, что это может быть атрибутом, который указывает, что класс является потокобезопасным, но его нет. Извините.