Функции файловых операций возвращаются, но фактически не фиксируются при завершении работы Windows.

Я работаю над приложением MFC, которое можно (среди прочего) использовать для выключения Windows. При этом Windows, конечно же, отправляет WM_QUERYENDSESSION и WM_ENDSESSION всем приложениям, включая мое. Однако проблема в том, что мое приложение в составе некоторых деструкторов удаляет определенные файлы (с помощью CFile::Remove), которые использовались во время выполнения. У меня есть основания полагать, что деструкторы вызываются (но это трудно сказать наверняка), когда приложение закрывается Windows.

Однако, когда Windows снова запускается, я иногда замечаю, что файлы, которые должны были быть удалены, все еще присутствуют. Это не происходит постоянно, даже когда выполнение программы идентично (у меня есть скрипт для проверки этого). Это наводит меня на мысль, что происходит одно из двух: либо а) деструкторы вызываются непоследовательно, либо б) функция удаления возвращается, но файл фактически не удаляется до закрытия Windows.

Единственный обходной путь, который я нашел до сих пор, заключается в том, что если я заставлю систему ждать с выключением примерно 10 секунд после остановки моей программы, то файлы будут правильно удалены. Это наводит меня на мысль, что b) может иметь место.

Я надеюсь, что кто-то сможет помочь мне с этой проблемой.

С уважением Морт


person Mort    schedule 30.01.2012    source источник
comment
Морт, добро пожаловать в Stack Overflow. Можно добиться большего прогресса, рекомендуя решение, когда вы публикуете свой код. В любом случае, есть ли у вас механизм ведения журнала (или точки ETW) для проверки того, что пути кода, которые, по вашему мнению, выполняются, действительно выполняются? CFile::Remove просто вызывает DeleteFile и может выдать исключение в случае сбоя. (Посмотрите на источник, чтобы понять, что я имею в виду) Возможно ли, что ваша программа завершается из-за неперехваченного исключения?   -  person selbie    schedule 30.01.2012
comment
Спасибо за ответ. Во-первых, я обрабатываю исключение, вызванное CFile::Remove, но мне еще предстоит увидеть, как это происходит на самом деле.   -  person Mort    schedule 30.01.2012
comment
Кроме того, я добавил ведение журнала. Когда я сравниваю два во всем остальном идентичных выполнения, одно, где файлы удалены, а другое, где их нет, я вижу, что файл журнала в последнем случае обрезается ближе к концу. Т.е. два файла журнала идентичны до определенного момента, после чего журнал экземпляра, где файлы не удаляются, просто останавливается (в этом случае деструкторы в соответствующих объектах не регистрируются). Поэтому я не могу точно знать, вызываются деструкторы или вызываются ли они, успешно или неудачно удаляются функции.   -  person Mort    schedule 30.01.2012


Ответы (3)


Как только ваша программа вернется из WM_ENDSESSION, Windows может завершить ее в любое время:

Если сеанс завершается, этот параметр имеет значение TRUE; сеанс может завершиться в любое время после того, как все приложения вернутся из обработки этого сообщения.

Если сеанс заканчивается быстро, он может закончиться до того, как запустятся ваши деструкторы. Вы должны выполнить всю свою очистку до возвращения из WM_ENDSESSION, потому что нет никакой гарантии, что у вас будет возможность сделать это позже.

person Raymond Chen    schedule 30.01.2012

Проблема здесь в том, что некоторые версии Windows сообщают о том, что операции по обработке файлов были завершены до того, как они на самом деле завершены. Это не проблема, если только не инициировано завершение работы, так как некоторые операции, включая удаление файлов, будут отменены.

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

person ChrisBD    schedule 30.01.2012
comment
Звучит странно. Вы имеете в виду, что в Windows есть ошибка, когда она не сбрасывает файловые операции при закрытии? - person valdo; 30.01.2012
comment
Я думал, что это могло иметь место, и мое подозрение подкрепляется тем фактом, что если я задерживаю выключение Windows в течение нескольких секунд (используя InitiateSystemShutdownEx с тайм-аутом), файлы всегда удаляются. Сокращение этого времени увеличивает вероятность того, что файлы не будут удалены. - person Mort; 30.01.2012

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

Таким образом, проблема заключается в том, что код пользовательского режима не вызывает DeleteFile или не работает (по какой-либо причине). Обратите внимание, что существует несколько способов выхода приложения (процесса), хотя не всегда вызываются d'tors. Есть автоматические объекты, которые уничтожаются в контексте их стека вызовов, плюс есть глобальные/статические объекты, которые инициализируются и уничтожаются кодом инициализации/очистки CRT.

Ниже приводится краткое описание способов завершения процесса с последствиями:

  • Все потоки процесса завершаются обычным образом (возвращаются из своей процедуры). ОС завершает процесс, в котором нет нитей. Все д’торы казнены.
  • Некоторые потоки либо выходят через ExitThread, либо уничтожаются TerminateThread. Автоматические объекты этих потоков не контролируются.
  • Процесс завершен пользователем ExitProcess. Автоматические объекты не уничтожаются, глобальные могут быть уничтожены (это происходит в CRT, используемом в DLL)
  • Процесс завершен TerminateProcess. Все d’tors не называются.

Я предлагаю вам проверить, действительно ли вызывается DeleteFile (или CFile::Remove, который его содержит), а также проверить, удается ли это. Например, вы можете открыть один и тот же файл дважды по любой причине.

person valdo    schedule 30.01.2012