Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Насчёт синхронизируемого объекта - lock(synchObject) / 25 сообщений из 32, страница 1 из 2
15.12.2015, 07:19
    #39127998
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Прочитал у Альбахари , что это обычно приватный объект:

авторThe synchronizing object is typically private (because this helps to encapsulate the locking logic)

Т. е. он разбирает какой-то конкретный случай, когда логика работы с многопоточными данными вся в одном классе инкапсулирована. А что, если мне эти данные надо давать использовать многим другим классам - т. е. сделать их публичными?

Например, у меня схема такая:

класс, который что-то делает (считает, например) - расчётный класс Calc;

класс, который хранит результаты и выводит их на экран:

Код: c#
1.
2.
3.
4.
class Result
{
    public List<double> ResultValues { get; set; }
}



Свойство ResultValues должно иметь многопоточный доступ - Calc постоянно пишет в это свойство, а Result постоянно читает из него и показывает результаты. Проблема в том, что ResultValues - постоянно обновляет свои данные по мере расчёта. При этом по мере расчёта надо показывать промежуточные результаты. Т. е. нужно как-то синхронизировать ResultValues между классами Calc и Result. А поскольку ResultValues это публичное свойство, то мне приходится придумывать некий синхронизирующий объект, который надо шарить между этими двумя классами. Я делаю это так - создаю класс приложения, в который помещаю объекты Calc, Results и синхронизирующий объект. Таким образом я могу расшарить один и тот же синхронизирующий объект между Calc и Result - передавать его через конструкторы этих классов или прямо в те их методы, который используют свойство ResultValues. Т. е. моя схема отличается от того, что говорит Альбахари, что логика синхронизации должна быть инкапсулирована в одном классе.

Я делаю всё правильно, или можно придумать схему лучше для моего случая?
...
Рейтинг: 0 / 0
15.12.2015, 07:22
    #39128001
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
А что, если сделать само свойство ResultValues синхронизируемым объектом, и везде, где используется это свойство - неважно, в своём классе, в котором объявлено это свойство, или в чужих - писать lock(ResultValues)?

Был ещё вариант, сделать это свойство приватным, но добавить публинчые обёртки над этим свойством, типа GetResultValues, AddNewValuesToResult и т. п., которые бы под локом делали бы свою работу. Но показалось, что это слишком мудрёный вариант, который мало что даёт.
...
Рейтинг: 0 / 0
15.12.2015, 07:24
    #39128002
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987А что, если сделать само свойство ResultValues синхронизируемым объектом, и везде, где используется это свойство - неважно, в своём классе, в котором объявлено это свойство, или в чужих - писать lock(ResultValues)?

Был ещё вариант, сделать это свойство приватным, но добавить публинчые обёртки над этим свойством, типа GetResultValues, AddNewValuesToResult и т. п., которые бы под локом делали бы свою работу. Но показалось, что это слишком мудрёный вариант, который мало что даёт.
Первый вариант плох тем, что невозможно заставить или как-то сообщить пользователю класса Result, что с ResultValues надо работать именно так. А второй хорош тем, что я заставляю пользователя ResultValues работать с ним только через методы, которые уже внутри используют блокировку.
...
Рейтинг: 0 / 0
15.12.2015, 07:27
    #39128004
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Возьми ConcurrentBag это тот же лист, только потокобезопасный.
Хотя тут очередь больше подойдет ConcurrentQueue

Все потокобезопасные классы
...
Рейтинг: 0 / 0
15.12.2015, 07:57
    #39128013
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Dima TВозьми ConcurrentBag это тот же лист, только потокобезопасный.
Хотя тут очередь больше подойдет ConcurrentQueue

Все потокобезопасные классы
Мне кажется, что потокобезопасные классы тут не очень подходят. Я уточню желательный сценарий использования ResultValues:

1) расчёт у меня работает циклически - приходит новая порция данных и класс Calc делает итерацию расчёта;

2) при каждой итерации класс Calc полностью обновляет ResultValues;

3) после каждой итерации класс Result считывает "снимок" ResultValues и выводит его на экран. Если не получается после каждой итерации считать, можно пропускать - главное, чтобы Result не считывал значения из ResultValues посередение заполнения ResultValues классом Calc.

В реальности я это реализую так - класс Calc молотит в бесконечном цикле while(true), ожидая новых данных и делая паузы посредством Thread.Sleep (думаю в будущем заменить на какой-нибудь SpinLock или Wait/Pulse, но пока так), класс Result делает то же самое - while(true) и Thread.Sleep. И оба класс работают с ResultValues через расшаренный синхронизирующий объект с помощью lock(synchObject).
...
Рейтинг: 0 / 0
15.12.2015, 07:58
    #39128014
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Т. е. из-за вот этого

AlexUser9872) при каждой итерации класс Calc полностью обновляет ResultValues;

3) после каждой итерации класс Result считывает "снимок" ResultValues

я не вижу смысла в потокобезопасных коллекциях в моём случае.
...
Рейтинг: 0 / 0
15.12.2015, 08:01
    #39128016
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987В реальности я это реализую так - класс Calc молотит в бесконечном цикле while(true), ожидая новых данных и делая паузы посредством Thread.Sleep (думаю в будущем заменить на какой-нибудь SpinLock или Wait/Pulse, но пока так), класс Result делает то же самое - while(true) и Thread.Sleep. И оба класс работают с ResultValues через расшаренный синхронизирующий объект с помощью lock(synchObject).
Да, забыл уточнить, что, естественно, каждый из классов Calc и Result работает в своём потоке. Точнее, в отдельных потоках запускаются методы этих классов, ответственные, соответственно, за расчёт и за вывод результатов.
...
Рейтинг: 0 / 0
15.12.2015, 08:26
    #39128028
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser9872) при каждой итерации класс Calc полностью обновляет ResultValues;

... главное, чтобы Result не считывал значения из ResultValues посередение заполнения ResultValues классом Calc.

Тогда генери в Calc новый List и присваивай по окончанию, т.е. так
Код: c#
1.
2.
3.
4.
5.
Calc() {
  var list = new List<double>();
  ... считаем, заполняем list
  ResultValues = list;
}


И не надо никаких синхронизаций. Можешь AutoResetEvent добавить для пробуждения Result
...
Рейтинг: 0 / 0
15.12.2015, 08:30
    #39128031
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Dima TИ не надо никаких синхронизаций. Можешь AutoResetEvent добавить для пробуждения Result
Почему не надо? А если класс Result перебирает элементы ResultValues, а в этом время класс Calc обновляет/подменяет ResultValues?

Т. е. в моём случае он обновляет данные в ResultValues, а в вашем - подменяет всю коллекцию новым объектом ResultValues. Но результат всё равно один - изменение коллекции ResultValues во время её перебора другим потоком.
...
Рейтинг: 0 / 0
15.12.2015, 08:34
    #39128033
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Я ещё думал создать для ResultValues коллекцию

List<List<double>> ResultValuesList

И чтобы после каждого расчёта Calc добавлял в ResultValuesList результаты, а Result бы забирал только последний на текущий момент элемент - т. е. последний результат. Ну и после каждого такого забора удаление из ResultValuesList всех предыдущих коллекций результатов, чтобы память не занимали. Как такой вариант? Тогда точно синхронизаций и блокировок не понадобится.
...
Рейтинг: 0 / 0
15.12.2015, 08:43
    #39128043
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987Dima TИ не надо никаких синхронизаций. Можешь AutoResetEvent добавить для пробуждения Result
Почему не надо? А если класс Result перебирает элементы ResultValues, а в этом время класс Calc обновляет/подменяет ResultValues?

Т. е. в моём случае он обновляет данные в ResultValues, а в вашем - подменяет всю коллекцию новым объектом ResultValues. Но результат всё равно один - изменение коллекции ResultValues во время её перебора другим потоком.
Результаты разные: в твоем случае объект один, в моем случае два разных, поэтому синхронизация не нужна.
Немного не дописал, чтобы в Result не сглючило лучше так
Код: c#
1.
2.
3.
4.
Result() {
   var list = ResultValues;
   ... выводим из list
}



Т.е. Calc() создал объект, наполнил, сохранил ссылку на объект в ResultValues и больше с объектом не работает. Result() взял ссылку из ResultValues и вывел. Точка пересечения Calc() и Result() только в передаче ссылки через ResultValues. Эта операция атомарная, т.е. не требует доп.синхронизаций (если путаю поправьте).
...
Рейтинг: 0 / 0
15.12.2015, 08:46
    #39128045
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987В реальности я это реализую так - класс Calc молотит в бесконечном цикле while(true), ожидая новых данных и делая паузы посредством Thread.Sleep
Черезжопная реализация. Sleep() - вставка тормоза чтоб проц в холостую не гонять. Разбирайся с источником данных, чтобы он будил Calc при появлении данных.
AlexUser987(думаю в будущем заменить на какой-нибудь SpinLock или Wait/Pulse, но пока так), класс Result делает то же самое - while(true) и Thread.Sleep. И оба класс работают с ResultValues через расшаренный синхронизирующий объект с помощью lock(synchObject).
Используй AutoResetEvent: Result висит на эвенте, Calc как посчитал и сохранил сбрасывает эвент, Result просыпается, выводит и дальше висит на эвенте.

PS Почитай Дж. Рихтер CLR via C# . Часть V. Многопоточность.
...
Рейтинг: 0 / 0
15.12.2015, 13:29
    #39128462
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Dima TAlexUser987пропущено...

Почему не надо? А если класс Result перебирает элементы ResultValues, а в этом время класс Calc обновляет/подменяет ResultValues?

Т. е. в моём случае он обновляет данные в ResultValues, а в вашем - подменяет всю коллекцию новым объектом ResultValues. Но результат всё равно один - изменение коллекции ResultValues во время её перебора другим потоком.
Результаты разные: в твоем случае объект один, в моем случае два разных, поэтому синхронизация не нужна.
Немного не дописал, чтобы в Result не сглючило лучше так
Код: c#
1.
2.
3.
4.
Result() {
   var list = ResultValues;
   ... выводим из list
}



Т.е. Calc() создал объект, наполнил, сохранил ссылку на объект в ResultValues и больше с объектом не работает. Result() взял ссылку из ResultValues и вывел. Точка пересечения Calc() и Result() только в передаче ссылки через ResultValues. Эта операция атомарная, т.е. не требует доп.синхронизаций (если путаю поправьте).
Да, вы правы - я упустил из виду

var list = new List<double>();

в классе Calc.

Спасибо и за другие советы - посмотрю.
...
Рейтинг: 0 / 0
15.12.2015, 13:30
    #39128463
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987var list = new List<double>();
...
Рейтинг: 0 / 0
15.12.2015, 14:21
    #39128570
Arm79
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Не вчитывался особо в суть проблемы,уверен, что задачу можно решить проще и по другому, но ответы на вопросы на всякий случай.

AlexUser987А что, если сделать само свойство ResultValues синхронизируемым объектом, и везде, где используется это свойство - неважно, в своём классе, в котором объявлено это свойство, или в чужих - писать lock(ResultValues)?
SyncRoot . Как раз тот же принцип. Все уже придумано до нас.

AlexUser987Был ещё вариант, сделать это свойство приватным, но добавить публинчые обёртки над этим свойством, типа GetResultValues, AddNewValuesToResult и т. п
Делается обычно так. В класс добавляются 2 метода. Например, Lock и UnLock. В Lock добавляем Monitor.Enter, в UnLock сами догадаетесь?

Применение:

Код: plaintext
1.
2.
3.
4.
5.
6.
MyObject.Lock();
try {
  ...
}
finally {
  MyObject.UnLock();
}


Но ценность таких вариантов достаточно сомнительна. В первую очередь нужно смотреть на возможность lock-free работы.
...
Рейтинг: 0 / 0
15.12.2015, 15:55
    #39128720
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Arm79Не вчитывался особо в суть проблемы,уверен, что задачу можно решить проще и по другому, но ответы на вопросы на всякий случай.

AlexUser987А что, если сделать само свойство ResultValues синхронизируемым объектом, и везде, где используется это свойство - неважно, в своём классе, в котором объявлено это свойство, или в чужих - писать lock(ResultValues)?
SyncRoot . Как раз тот же принцип. Все уже придумано до нас.

AlexUser987Был ещё вариант, сделать это свойство приватным, но добавить публинчые обёртки над этим свойством, типа GetResultValues, AddNewValuesToResult и т. п
Делается обычно так. В класс добавляются 2 метода. Например, Lock и UnLock. В Lock добавляем Monitor.Enter, в UnLock сами догадаетесь?

Применение:

Код: plaintext
1.
2.
3.
4.
5.
6.
MyObject.Lock();
try {
  ...
}
finally {
  MyObject.UnLock();
}


Но ценность таких вариантов достаточно сомнительна. В первую очередь нужно смотреть на возможность lock-free работы.
Про синк рут спасибо. Про дальнейшее - что-то сомнительным выглядит. Как заставить пользователя класса пользоваться моим классом именно по такой сложной схеме? С таким же успехом можно заставить его самостоятельно локать свойства-коллекции этого класса - т. е. никак. Разве что в комментариях или документации к классу очень сильно попросить, что делать надо именно так, а не иначе, а если нет, то будет упс.
...
Рейтинг: 0 / 0
15.12.2015, 16:02
    #39128733
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Про синк рут полезная вещь. Просто на самом деле я упростил свой пример и у меня по смыслу не одна коллекция пишется-читается, а несколько, поэтому выделить специальный объект под синхронизацию ВСЕГО этого дела в виде "атомарной" операции под локом кажется более подходящим.

А вообще, как поступить, если в моём классе Result не просто одна коллекция, которую постоянно целиком обновляет другой класс, а нечто смешанное? Например, у меня вот такая коллеция, как выше описана - т. е. полностью обновляющаяся в каждой итерации расчёта. Потом ещё другая коллеция, которая лишь добавляет очередную пачку рассчитанных данных в конец уже существующих - т. е. пополняющиеся результаты. Плюс ещё просто числа, которые обновляются. И вот весь этот набор надо бы защищить от изменения классом расчёта Calc, пока его класс результатов Result выводит на экран. Тут удобнее всё это под одним общим локом разместить, или как? Или к каждому типу данных свой подход - где-то volatile, где-то из concurrent collection взять, а где-то через lock сделать? Я вот пока реализовал - всё изменения и чтения всех этих разношёрстных результатов поместил под одним общим lock.
...
Рейтинг: 0 / 0
15.12.2015, 17:08
    #39128865
Arm79
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987Я вот пока реализовал - всё изменения и чтения всех этих разношёрстных результатов поместил под одним общим lock.
Работает? Проблем по скорости нет? Никто не жалуется? Значит, нормально.
Сделайте хоть как то, чтобы работало, потом рефакторьте код.
...
Рейтинг: 0 / 0
15.12.2015, 17:27
    #39128888
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Arm79AlexUser987Я вот пока реализовал - всё изменения и чтения всех этих разношёрстных результатов поместил под одним общим lock.
Работает? Проблем по скорости нет? Никто не жалуется? Значит, нормально.
Сделайте хоть как то, чтобы работало, потом рефакторьте код.
Да давно уже работает. Я вот откопал своё старьё и думаю, как получше сделать. Т. к. скоро что-то подобное придётся снова делать - думаю, не повторять же то же самое. Может, получше варианты есть. Так сказать, общие подходы. Тот же Альбахари про это, вроде, ничего не пишет. В этом вашем Рихтере есть что подобное?
...
Рейтинг: 0 / 0
15.12.2015, 18:03
    #39128937
Arm79
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Dima TТочка пересечения Calc() и Result() только в передаче ссылки через ResultValues. Эта операция атомарная, т.е. не требует доп.синхронизаций (если путаю поправьте).
ставьте volatile и должно быть норм.
...
Рейтинг: 0 / 0
15.12.2015, 18:04
    #39128943
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987В этом вашем Рихтере есть что подобное?
Почитай, хуже не будет. ХЗ есть или нет, слишком уж абстрактно у тебя задача сформулирована. По крайней мере узнаешь о всех возможных альтернативах решения твоей задачи.

Как выше упомянули надо в сторону lock-free идти (в моих примерах оно самое).
Закон Амдала никто не отменял, поэтому чем больше синхронизируешься, тем меньше пользы от распараллеливания.
...
Рейтинг: 0 / 0
15.12.2015, 18:08
    #39128951
Arm79
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987,

А каждая порция данных от Calc должна быть обработана Result?
...
Рейтинг: 0 / 0
15.12.2015, 18:45
    #39129014
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Arm79AlexUser987,

А каждая порция данных от Calc должна быть обработана Result?
Нет.

Result делает слепок с набора результатов и потом сразу "освобождает" (в смысле, что перестаёт использовать - считывать значения там и прочее) этот набор, чтобы Calc дальше мог в него писать. В момент создания слепка я и применяю блокировку через lock. После создания слепка Result неспешно выводит результаты из этого слепка на экран. Неспешно в том смысле, что копирование данных в слепок происходит гораздо быстрее, чем отображение на экране. В этом время Calc под локом пишет в набор результатов, которые только что освободил Result. Обычно у меня получается, что Calc может множество итераций расчёта провести на одну итерацию вывода результатов - т. е. он несколько раз перезапишет набор результатов. Поэтому Result берёт слепок всегда с последней версии результатов. Это нужно, чтобы результаты отображались в реальном времени - с приемлемой задержкой по отношению к поступающим данным.

Задачи показать вывод именно по всем результатам у меня пока нет. Если будет - переделаю, чтобы результаты накапливались в коллекции.
...
Рейтинг: 0 / 0
15.12.2015, 18:48
    #39129023
AlexUser987
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
Dima T Закон Амдала
Кстати, он показывает, что технологической сингулярности не будет. Даже если доведут до ума квантовые компьютеры. Но будет некоторое приближение к ней. Довольно близкое и болезненное.
...
Рейтинг: 0 / 0
15.12.2015, 18:57
    #39129040
Arm79
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Насчёт синхронизируемого объекта - lock(synchObject)
AlexUser987,

Элементов в наборе данных много? десятки? сотни? тысячи? миллионы?
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Насчёт синхронизируемого объекта - lock(synchObject) / 25 сообщений из 32, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]