Здравствуйте, Sinix, Вы писали:
S>Класс SomeTask может быть в двух состояниях:
S>- простаивает (можно изменять любые свойства, косяки с многопоточными обновлениями — проблемы вызывающего кода)
S>- работает (любые попытки изменить свойства/повторно запустить задачу, даже из другого потока — InvalidOperationException).
S>Чугуниевый прототип: S>
.....
S>
S>Как бы сделали вы?
Так же сделал бы, чем приведенный код самому не нравится?
S> public class SomeTask
S> {
S> privatevolatilebool isBusy;
S> private void ValidateNotBusy()
S> {
S> lock (lockKey)
S> {
S> if (isBusy)
S> {
S> throw new InvalidOperationException("blablabla");
S> }
S> }
S> }
S>
S>Как бы сделали вы?
выкинул ms выделенную блокировку, есть в аругментах InvalidOperationException не используются члены класса требующие доступа с блокировкой
Здравствуйте, achmed, Вы писали:
A>Так же сделал бы, чем приведенный код самому не нравится?
А вот хз... корявый он какой-то: смесь lock с volatile конечно работает, но выглядит странно Как вариант, можно заменить доступ к полю на Interlocked.*, но здесь это будет выглядеть скорее понтами, чем обоснованным решением. А, ну да, ещё можно извратиться с RWLockSlim
Просто подозреваю что кто-то подобную задачу решал и придумал решение посимпатичней
По-моему, у Вас не разруливается ситуация, в которой Run вызывается в момент, когда кто-то находится внутри сеттера. Если это возлагается на внешний код, то и lock для доступа к isBusy вроде как не нужен. Ну а так, я-бы скорее всего на Interlocked ориентировался.
Здравствуйте, Sinix, Вы писали:
S>- простаивает (можно изменять любые свойства, косяки с многопоточными обновлениями — проблемы вызывающего кода) S>- работает (любые попытки изменить свойства/повторно запустить задачу, даже из другого потока — InvalidOperationException).
S>Как бы сделали вы?
Свойства — по аналогии с DependencyProperty, только не статическими, а экземплярными.
Без секции, к сожелению, никак: надо же сначала проверить, а затем изменить значение.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Jolly Roger, Вы писали:
JR>По-моему, у Вас не разруливается ситуация, в которой Run вызывается в момент, когда кто-то находится внутри сеттера.
Да, именно так, щас пытаюсь сообразить, сильно ли это критично. Пока выходит, что нет.
Здравствуйте, Sinix, Вы писали:
S>Да, именно так, щас пытаюсь сообразить, сильно ли это критично. Пока выходит, что нет.
Мне кажется это странным Вот смотрите, кто-то входит в сеттер, успешно проходит ValidateNotBusy() и сразу после неё планировщик отбирает у этого потока управление. Далее другой поток вызывает Run и уходит в недра LongRunningMethod(). В какой-то момент первый поток опять получает доступ к процессору и изменяет поле. По-моему, это ничем не отличается от вызова сеттера во время работы Run, от чего Вы вроде как пытаетесь защититься
Здравствуйте, Jolly Roger, Вы писали:
JR>Мне кажется это странным
Ну да, криво, надо оборачивать в lock весь setter (_Fred_ выше тоже предложил аналогичное решение).
Класс действительно внутренний и его инициализацию и запуск задач разделяет большой промежуток времени. Но проще сразу сделать хорошо, чем потом
Здравствуйте, Sinix, Вы писали:
S>Ну да, криво, надо оборачивать в lock весь setter (_Fred_ выше тоже предложил аналогичное решение).
Ну да, вобщем-то. Плохо только, что это потребует одного локера на все свойства, что плохо скажется на параллелизме. Я-бы всё-таки рассмотрел использование RWLockSlim или собственной похожей реализации, заточенной под данную ситуацию, заодно обдумав желательность и возможность снять с внешнего кода ответственность за синхронизацию доступа к свойствам.
Здравствуйте, Jolly Roger, Вы писали:
JR>Ну да, вобщем-то. Плохо только, что это потребует одного локера на все свойства, что плохо скажется на параллелизме.
Ну да. Код давно жил, потом как всегда внезапно появилась многопоточность и тут же под неё приходится наворачивать инфраструктуру
Здравствуйте, Sinix, Вы писали:
S>Класс SomeTask может быть в двух состояниях:
S>- простаивает (можно изменять любые свойства, косяки с многопоточными обновлениями — проблемы вызывающего кода)
S>- работает (любые попытки изменить свойства/повторно запустить задачу, даже из другого потока — InvalidOperationException).
Паттерн автомат состояний?
public class SomeTask
{
public SomeTask()
{
this.state = new SettingState();
}
private volatile ITaskBackend state;
#region Public properties
public bool IsBusy
{
get
{
return state.IsRunning;
}
}
public string SomeOption
{
get
{
return state.SomeOption;
}
set
{
state.SomeOption = value;
}
}
#endregion
#region Core logic
public void Run()
{
state = state.BeginRun();
try
{
LongRunningMethod();
}
finally
{
state = state.EndRun();
}
}
#endregion
}
interface ITaskBackend
{
string SomeOption { get; set; }
bool IsRunning { get; }
ITaskBackend BeginRun();
ITaskBackend EndRun();
}
class SettingState : ITaskBackend
{
public string SomeOption { get; set; }
public bool IsRunning { get { return false; } }
public ITaskBackend BeginRun()
{
return new RunningState(SomeOption);
}
public ITaskBackend EndRun()
{
throw new InvalidOperationException();
}
}
class RunningState : ITaskBackend
{
public RunningState(string someOption)
{
this.someOption = someOption;
}
private readonly string someOption;
public string SomeOption {
get { return someOption; }
set { throw new InvalidOperationException(); }
}
public bool IsRunning { get { return true; } }
public ITaskBackend BeginRun()
{
throw new InvalidOperationException();
}
public ITaskBackend EndRun()
{
return new SomeOption();
}
}
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, hardcase, Вы писали:
S>Вах, я ведь такой подход видел — его Transaction внутри себя использует. Весьма красиво
Вообще синхронизация все же нужна, но только в одном месте:
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Wolverrum, Вы писали:
W>>Внесу свою архинеизящную лепту
S>Постшарп небось?
Ато!
Хотя ТС лев (неправ) архитектурно, имхо, если уж морозиться в рамках ООП, то к объекту следовало бы иметь строго одну точку доступа, которая предоставляла бы интерфейс для работы с объектом. Или не предоставляла — это уже по ситуации
W>Хотя ТС лев (неправ) архитектурно, имхо, если уж морозиться в рамках ООП, то к объекту следовало бы иметь строго одну точку доступа, которая предоставляла бы интерфейс для работы с объектом. Или не предоставляла — это уже по ситуации
ТС — это я И да, идея с паттерном состояния мне пока что нравится больше всего. Поскольку у базового класса туча наследников, может проще окажется _сначала_ переизобрести dependency properties, а _затем_ — реализовать вариант hardcase. В результате получится как раз Freezable из WPF