программистское
Jan. 25th, 2006 01:30 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
попал на забавный клин в синглетоне: функция getInstance() может быть вызвана из-под конструктора, вызваного опять же из функции getInstance() для того же самого класса. Не обязательно напрямую, разумеется, а через цепочку вызовов. В моём случае всё было еще сложнее: getInstance() обратилась к кому-то там через COM, и пока вызов отрабатывался, в тот же тред пришел другой COM-вызов (вот не понимаю, зачем микрософт такое разрешил), приведший к новому вызову getInstance().
Иными словами
1. функция getInstance для класса T вызвается в самый первый раз
2. вызывается конструктор класса Т
3. конструктор вызывает еще что-то-там
4. что-то-там вызывает getInstance для класса Т
Вроде бы, ни в одной книжной имплементации синглетона я не видел защиты от подобного сценария, или упоминания о нём.
Иными словами
1. функция getInstance для класса T вызвается в самый первый раз
2. вызывается конструктор класса Т
3. конструктор вызывает еще что-то-там
4. что-то-там вызывает getInstance для класса Т
Вроде бы, ни в одной книжной имплементации синглетона я не видел защиты от подобного сценария, или упоминания о нём.
no subject
Date: 2006-01-25 11:40 am (UTC)no subject
Date: 2006-01-25 11:44 am (UTC)no subject
Date: 2006-01-25 01:13 pm (UTC)Проблема как раз и была в STA: когда STA делает call наружу, она ожидает его результата, но при этом может принять не только callback (что естественно), но и внешний call (с иной causality).
Но вообще, речь не столько о том, как починить, а о том, как "словить" подобную проблему, коль скоро она возникнет. Известные мне имплементации синглетона это не делают, хотя только они, а не их пользователь, и могут это сделать.
no subject
Date: 2006-01-25 01:21 pm (UTC)no subject
Date: 2006-01-25 01:34 pm (UTC)Лучше уж такую ошибку отлавливать, что и было сделано, естественно.
no subject
Date: 2006-01-25 01:37 pm (UTC)no subject
Date: 2006-01-25 01:44 pm (UTC)по-моему, ровно наоборот.
no subject
Date: 2006-01-25 01:47 pm (UTC)no subject
Date: 2006-01-25 02:52 pm (UTC)no subject
Date: 2006-01-25 02:56 pm (UTC)no subject
Date: 2006-01-25 03:03 pm (UTC)Но тогда выходит, что синглетон лучше вообще не применять, не так ли? (ну, кроме как для возврата чего-то подобного Class Object в С++).
Или есть еще какие-то критерии?
no subject
Date: 2006-01-25 03:14 pm (UTC)no subject
Date: 2006-01-25 02:07 pm (UTC)no subject
Date: 2006-01-25 02:11 pm (UTC)no subject
Date: 2006-01-25 02:14 pm (UTC)no subject
Date: 2006-01-25 02:18 pm (UTC)Ну, это уже зависит от конкретной задачи. Если задача позволяет подождать - можно и подождать (вот только на чем ждать - семафор какой-то нужен, да? А где его инициализировать? Курица и яйцо).
Либо может пробросить его (исключение) дальше - либо должен возвращать статус, а референс - через out argument.
no subject
Date: 2006-01-25 02:26 pm (UTC)Ну, задача-то вряд ли может НЕ позволить ждать, поскольку для её решения нужен объект, который пока не сконструирован. Если речь идёт о срочной задаче, то там возврат ошибки выглядит совершенно естественно - для решения нужен объект, недоступный в допустимых временных рамках. Другое дело - объект, который принципиально не может быть сконструирован, ибо процесс его конструкции предполагает наличие его уже сконструированного и готового к употреблению...
(вот только на чем ждать - семафор какой-то нужен, да? А где его инициализировать? Курица и яйцо).
Ну, это-то уже проблема имплементации, вполне решаемая притом (хотя решение получается довольно уродливым, по меньшей мере, у меня).
Либо может пробросить его (исключение) дальше - либо должен возвращать статус, а референс - через out argument.
А Вы бы сами хотели пользоваться такой функцией getInstance? :)
no subject
Date: 2006-01-25 02:30 pm (UTC)Задачи разные бывают. Можно себе представить задачу, в которой вторичный вызов getInstance в процессе создания синглетона является ошибкой - и должен закончиться остановкой программы. О цикличном вызове я и не говорю - это просто тривиальный (ну, или не очень тривиальный) баг.
Почему бы и нет? Весь COM на таких функциях построен. Возможность отрапортовать об ошибке (и проверка наличия ошибки) - нормальная практика, к сожалению, не всегда соблюдающаяся. Хотя, конечно, исключения удобней во многих ситуациях.
no subject
Date: 2006-01-25 12:50 pm (UTC)no subject
Date: 2006-01-25 01:14 pm (UTC)no subject
Date: 2006-01-25 01:35 pm (UTC)no subject
Date: 2006-01-25 01:43 pm (UTC)но подобное могло возникнуть и на другом объектном языке программирования,
равно как и на другом необъектном языке. Да хоть и на ассемблере.
no subject
Date: 2006-01-25 01:50 pm (UTC)Но обычно на ассемблере ОО не пишут (хотя, естественно, можно, и даже, более того, это просто). И на С ОО используется самое большее на стадии дизайна. Как-то С++ больше для ОО подходит (о Жабе я и не говорю, она для другого не приспособлена).
no subject
Date: 2006-01-25 02:03 pm (UTC)no subject
Date: 2006-01-25 02:12 pm (UTC)no subject
Date: 2006-01-25 02:12 pm (UTC)