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

автор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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128001
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А что, если сделать само свойство ResultValues синхронизируемым объектом, и везде, где используется это свойство - неважно, в своём классе, в котором объявлено это свойство, или в чужих - писать lock(ResultValues)?

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

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

Все потокобезопасные классы
...
Рейтинг: 0 / 0
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128013
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128014
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Т. е. из-за вот этого

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

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

я не вижу смысла в потокобезопасных коллекциях в моём случае.
...
Рейтинг: 0 / 0
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128016
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlexUser987В реальности я это реализую так - класс Calc молотит в бесконечном цикле while(true), ожидая новых данных и делая паузы посредством Thread.Sleep (думаю в будущем заменить на какой-нибудь SpinLock или Wait/Pulse, но пока так), класс Result делает то же самое - while(true) и Thread.Sleep. И оба класс работают с ResultValues через расшаренный синхронизирующий объект с помощью lock(synchObject).
Да, забыл уточнить, что, естественно, каждый из классов Calc и Result работает в своём потоке. Точнее, в отдельных потоках запускаются методы этих классов, ответственные, соответственно, за расчёт и за вывод результатов.
...
Рейтинг: 0 / 0
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128028
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128031
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИ не надо никаких синхронизаций. Можешь AutoResetEvent добавить для пробуждения Result
Почему не надо? А если класс Result перебирает элементы ResultValues, а в этом время класс Calc обновляет/подменяет ResultValues?

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

List<List<double>> ResultValuesList

И чтобы после каждого расчёта Calc добавлял в ResultValuesList результаты, а Result бы забирал только последний на текущий момент элемент - т. е. последний результат. Ну и после каждого такого забора удаление из ResultValuesList всех предыдущих коллекций результатов, чтобы память не занимали. Как такой вариант? Тогда точно синхронизаций и блокировок не понадобится.
...
Рейтинг: 0 / 0
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128043
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128045
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128462
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128463
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlexUser987var list = new List<double>();
...
Рейтинг: 0 / 0
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128570
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128720
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Насчёт синхронизируемого объекта - lock(synchObject)
    #39128733
AlexUser987
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Про синк рут полезная вещь. Просто на самом деле я упростил свой пример и у меня по смыслу не одна коллекция пишется-читается, а несколько, поэтому выделить специальный объект под синхронизацию ВСЕГО этого дела в виде "атомарной" операции под локом кажется более подходящим.

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

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

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

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

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

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

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


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