Как в многопоточном программировании обрабатываются вложенные объекты?
Вопрос больше касается C#, но подойдут ответы с других языков - важен принцип. Если вопрос окажется непонятным - прошу уточнять.
Пример:
объект 1
- объект 2
объект 3
- объект 2
объект 4
- объект 1
объект 5
- объект 3
4 мутирует 1, а внутри обращается к 2.
5 мутирует 3, но затем также обращается к 2.
Объекты 4 и 5 работают в разных потоках. Мьютекс обеспечивает экран для объектов 1 и 3, но те в свою очередь обращаются к неэкранированному общему объекту 2
Вопрос: как правильно расставлять блокировки, чтобы с одной стороны не пропустить таких ситуаций, а с другой - не начать мутировать каждый объект в программе.
Объекты в единственном числе и содержат поля которые изменяются из разных мест параллельно?
Объекты вложенные или нет обрабатываются одинаково, вся проблема заключается в доступе к одному и тому же адресу в памяти на запись одновременно из разных потоков выполнения, когда многоядерный процессор пытается разными ядрами писать по одному адресу.
Такими адресами являются поля объектов.
Да, все объекты в единственном числе. Пример показывает вложенность переменных, содержащих на них адреса. Объекты 4 и 5 работают в разных потоках. Мьютекс обеспечивает экран для объектов 1 и 3, но те в свою очередь обращаются к неэкранированному общему объекту 2. Понимаю, что логичным реением может показаться обернуть второй объект мьютексами, но я предполагаю, что такие ошибки могут возникнуть при большей вложенности. Или я ошибаюсь и при грамотной архитектуре такого возникнуть не может? На что нужно обращать внимание, чтобы грамотно выстраивать архитектуру приложения?
Виталий: Если объекты не передают между собой данные, а просто изменяют их независимо, и эти поля являются простыми типами данных то можно использовать интерлокед. Т.к. все равно первым отработает поток который пришел из объекта А или объекта Б.
Если предыдущий объект передает что либо следующему, и эту транзакцию нельзя прерывать другой, то тут сложнее. Я бы подумал над паттерном "команда" или вспомнил что там еще есть. Возможно проще такие дела передавать как команды в пул команд, и он уже знает какая команда в процессе выполнения и какие объекты в ней участвуют. Если объекты участники новой команды не пересекаются с уже задействованными то ее можно стартануть, или пусть ожидает освобождения всех используемых объектов. Иначе новая команда изменить состояние объекта который в процессе выполнения в другой команде, и не очень просто будет разобраться что из этого выйдет.
Спешить тут точно не стоит, 10 раз все продумать на бумаге с ручкой.
Тут еще вопрос в том, а нужна ли такая параллельность, какой выигрыш от нее и сложность решения.
Зачем параллелить то что выполняется и так очень быстро, резона не будет, поток дороже стоит чем операция им выполняемая.
А "команда" позволит мониторить и логировать все что происходит в программе, новый человек за пару минут сможет понять как оно работает.