yigal_s: (Default)
[personal profile] yigal_s
попал на забавный клин в синглетоне: функция getInstance() может быть вызвана из-под конструктора, вызваного опять же из функции getInstance() для того же самого класса. Не обязательно напрямую, разумеется, а через цепочку вызовов. В моём случае всё было еще сложнее: getInstance() обратилась к кому-то там через COM, и пока вызов отрабатывался, в тот же тред пришел другой COM-вызов (вот не понимаю, зачем микрософт такое разрешил), приведший к новому вызову getInstance().

Иными словами
1. функция getInstance для класса T вызвается в самый первый раз
2. вызывается конструктор класса Т
3. конструктор вызывает еще что-то-там
4. что-то-там вызывает getInstance для класса Т


Вроде бы, ни в одной книжной имплементации синглетона я не видел защиты от подобного сценария, или упоминания о нём.

Date: 2006-01-25 11:40 am (UTC)
From: [identity profile] solomon2.livejournal.com
Против (бесконечно-рекурсивного) лома нет приема :-)

Date: 2006-01-25 11:44 am (UTC)
From: [identity profile] dimrub.livejournal.com
Можно сериализовать COM запросы в поток, используя STA.

Date: 2006-01-25 01:21 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Ну, в таком случае, наверное не стоит делать так, чтобы конструктор синглтона делал какие-то сложные вещи (вроде вызовов COM). Ну и можно, в принципе, поставить защиту в getInstance, чтобы он не только проверял равенство статического указателя нулю, но еще и изменял атомным образом какую-то статическую переменную - тогда и до возврата конструктора getInstance будет знать, что он уже был вызван - и сможет, например, вернуть ошибку.

Date: 2006-01-25 01:37 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Библиотечный класс синглетон doesn't sound like a good idea :)

Date: 2006-01-25 01:47 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Есть основания полагать, что легкость использования синглетона не позволит некоторым программистам вовремя подумать о его уместности. Хотя, конечно, от конкретных обстоятельств многое зависит.

Date: 2006-01-25 02:56 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Ну, много может быть ситуаций, в которых программист в начале работы полагает, что у него может быть только одна штука какого-то объекта, а потом требования меняются - и ему приходится много чего переделывать.

Date: 2006-01-25 03:14 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Честно говоря, затрудняюсь придумать какие-то общие правила. Думаю, тут каждый должен сам решать, в каких направлениях его проект может развиться - и чего ему это будет стоить.

Date: 2006-01-25 02:07 pm (UTC)
From: [identity profile] disbalanced.livejournal.com
Есть в этом что-то. Если в ходе конструирования объекта предполагается, что он уже сконструирован, налицо прокол в (извините за выражение) дизайне. Интересно понять, как такую ситуацию корректно отработать - ведь возврат ошибки означает провал конструирования синглетона из-за того, что его на тот момент не существовало :) (не говоря уже о милой проблеме возврата ошибки из конструктора).

Date: 2006-01-25 02:11 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Как раз с возвратом ошибки из конструктора нет проблем: конструктор бросает исключение, которое getInstance ловит и обрабатывает. Проблема именно с вызовом getInstance в процессе работы конструктора - из другого потока.

Date: 2006-01-25 02:14 pm (UTC)
From: [identity profile] disbalanced.livejournal.com
Из другого потока не страшно - можно подождать. Проблема возникает тогда, когда дело происходит в том же самом потоке. Кстати, а как getInstance может обработать такое исключение? Вернёт NULL? А если она возвращает не указатель, а reference?

Date: 2006-01-25 02:18 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Из другого потока не страшно - можно подождать.

Ну, это уже зависит от конкретной задачи. Если задача позволяет подождать - можно и подождать (вот только на чем ждать - семафор какой-то нужен, да? А где его инициализировать? Курица и яйцо).

Кстати, а как getInstance может обработать такое исключение? Вернёт NULL? А если она возвращает не указатель, а reference?

Либо может пробросить его (исключение) дальше - либо должен возвращать статус, а референс - через out argument.

Date: 2006-01-25 02:26 pm (UTC)
From: [identity profile] disbalanced.livejournal.com
Ну, это уже зависит от конкретной задачи. Если задача позволяет подождать - можно и подождать.
Ну, задача-то вряд ли может НЕ позволить ждать, поскольку для её решения нужен объект, который пока не сконструирован. Если речь идёт о срочной задаче, то там возврат ошибки выглядит совершенно естественно - для решения нужен объект, недоступный в допустимых временных рамках. Другое дело - объект, который принципиально не может быть сконструирован, ибо процесс его конструкции предполагает наличие его уже сконструированного и готового к употреблению...

(вот только на чем ждать - семафор какой-то нужен, да? А где его инициализировать? Курица и яйцо).
Ну, это-то уже проблема имплементации, вполне решаемая притом (хотя решение получается довольно уродливым, по меньшей мере, у меня).

Либо может пробросить его (исключение) дальше - либо должен возвращать статус, а референс - через out argument.
А Вы бы сами хотели пользоваться такой функцией getInstance? :)

Date: 2006-01-25 02:30 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Ну, задача-то вряд ли может НЕ позволить ждать

Задачи разные бывают. Можно себе представить задачу, в которой вторичный вызов getInstance в процессе создания синглетона является ошибкой - и должен закончиться остановкой программы. О цикличном вызове я и не говорю - это просто тривиальный (ну, или не очень тривиальный) баг.

А Вы бы сами хотели пользоваться такой функцией getInstance? :)

Почему бы и нет? Весь COM на таких функциях построен. Возможность отрапортовать об ошибке (и проверка наличия ошибки) - нормальная практика, к сожалению, не всегда соблюдающаяся. Хотя, конечно, исключения удобней во многих ситуациях.

Date: 2006-01-25 12:50 pm (UTC)
From: [identity profile] peresmeshnik.livejournal.com
Ужос этот ваш С++...

Date: 2006-01-25 01:35 pm (UTC)
From: [identity profile] peresmeshnik.livejournal.com
А что, это не С++? Звучит как типичное описание сидвуплясной штуки: синглтон + конструктор + класс.

Date: 2006-01-25 01:50 pm (UTC)
From: [identity profile] peresmeshnik.livejournal.com
Да, конечно.
Но обычно на ассемблере ОО не пишут (хотя, естественно, можно, и даже, более того, это просто). И на С ОО используется самое большее на стадии дизайна. Как-то С++ больше для ОО подходит (о Жабе я и не говорю, она для другого не приспособлена).

Date: 2006-01-25 02:12 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Я писал синглтоны на Яве. Точно так же их можно писать (и пишут) на C# и на многих других OO языках.

Date: 2006-01-25 02:12 pm (UTC)
From: [identity profile] dimrub.livejournal.com
Да, и на C, кстати, тоже.