Я работаю с Visual Studio 2008 на стандартном (неуправляемом) C ++ под Windows XP Pro SP 3.
Я создал потокобезопасную оболочку вокруг std :: cout. Этот объект-обертка является заменой (то есть с тем же именем) для использования в качестве макроса, который # был определен для cout. Используется лот кода. Его поведение, вероятно, в значительной степени, как вы ожидаете:
При строительстве создается критический участок.
Во время вызовов оператора << () он блокирует критическую секцию, передает данные для печати в cout и, наконец, освобождает критическую секцию. </p>
При разрушении разрушает критическую секцию.
Эта оболочка находится в статическом хранилище (оно глобально). Как и все такие объекты, он создается до запуска main () и разрушается после выхода из main ().
Использование моей обертки в деструкторе другого объекта, который также находится в статическом хранилище, проблематично. Поскольку порядок строительства / уничтожения таких объектов не определен, я вполне могу попытаться заблокировать критический участок, который был уничтожен. Симптом, который я вижу, заключается в том, что моя программа блокируется при попытке блокировки (хотя я предполагаю, что что-то может произойти).
Что касается способов справиться с этим ...
Я ничего не мог сделать в деструкторе; в частности, я бы позволил критическому разделу продолжать жить. Стандарт C ++ гарантирует, что cout никогда не умирает во время выполнения программы, и это будет наилучшей из возможных попыток заставить мою оболочку вести себя аналогично. Конечно, моя оболочка «официально» умерла бы после запуска пустого деструктора, но, вероятно, (я ненавижу это слово) была бы такой же функциональной, как и до запуска деструктора. На моей платформе это действительно так. Но, черт возьми, это уродливо, непереносимо и может сломаться в будущем ...
Я держу критическую секцию (но не ссылку на поток в cout) в pimpl. Всем критическим доступам к разделу через pimpl предшествует проверка ненулевого значения pimpl. Случилось так, что я забыл установить pimpl в 0 после вызова delete для него в деструкторе. Если бы я должен был установить это значение в 0 (что я должен делать в любом случае), вызовы в мою обертку после ее разрушения ничего бы не сделали с критической секцией, но все равно передадут данные для печати в cout. На моей платформе это также, кажется, работает. Опять уродливый ...
Я мог бы сказать своим товарищам по команде не использовать мою оболочку после выхода из main (). К сожалению, аэродинамика этого будет примерно такой же, как у танка.
ВОПРОСЫ:
* Вопрос 1 *
В случае 1, если я оставлю критический раздел не уничтоженным, произойдет утечка ресурсов критического раздела в ОС. Будет ли эта утечка сохраняться после полного завершения моей программы? Если нет, дело 1 становится более жизнеспособным.
* Вопрос 2 *
Для случаев 1 и 2, кто-нибудь знает, если на моей конкретной платформе , действительно ли я смогу безопасно продолжать использовать свою оболочку после запуска ее пустого деструктора? Кажется, я могу, но я хочу посмотреть, знает ли кто-нибудь что-то определенное о том, как ведет себя моя платформа в этом случае ...
* Вопрос 3 *
Мои предложения явно несовершенны, но я не вижу по-настоящему правильного решения. Кто-нибудь знает правильное решение этой проблемы?
Примечание: Конечно, может возникнуть обратная проблема, если я попытаюсь использовать свою оболочку в конструкторе другого объекта, который также находится в статическом хранилище. В этом случае я могу попытаться заблокировать критический раздел, который еще не был создан. Я хотел бы использовать идиому «конструкция при первом использовании», чтобы исправить это, но это влечет за собой синтаксическое изменение всего кода, который использует мою обертку. Это потребует отказа от естественности использования оператора <<. И слишком много кода, чтобы изменить в любом случае. Так что это нереальный вариант. Я не очень углублен в мыслительный процесс по этой половине проблемы, но я задам один вопрос, который может быть частью другого несовершенного способа решения проблемы ... </p>
* Вопрос 4 *
Как я уже сказал, моя обертка живет в статическом хранилище (оно глобально) и имеет прыщ (гормональная проблема :)). У меня сложилось впечатление, что необработанные байты переменной в статическом хранилище устанавливаются в 0 во время загрузки (если не инициализированы по-разному в коде). Это будет означать, что pimpl моей оболочки имеет значение 0 до создания моей оболочки. Это правильно?
Спасибо,
Dave