Новый QFile("some.txt") завершается ошибкой с "устройство не открыто", когда экран Windows заблокирован

Рассмотрим этот очень простой пример:

for(;;){
   QFile *file = new QFile("some.txt");//this is where it fails with "device not open" when windows screen is locked
   if(file->exists()){
      file->open(QFile::ReadOnly);
      QString contents = file->readAll();
      file->close();
   }
   file->deleteLater();
   QThread::sleep(2);
}

До недавнего времени он продолжал работать как обычно, когда экран Windows был заблокирован, но я не уверен, начал ли он работать так, потому что я начал использовать Qt 5.9 или это было обновление Windows, предотвращающее доступ к файлам, пока экран Windows работает. заперта.

Поэтому, пожалуйста, посоветуйте обходной путь или решение. Спасибо.

Изменить: Оказывается, что QFile или доступ к файлу не было проблемой, и проблема была, где и кем он был вызван. Поэтому я принимаю ответ @Kuba, поскольку он был информативным и в правильном направлении.

1 ответ

Решение

Ваш код утечки памяти и ресурсов: QFile экземпляры никогда не будут уничтожены, так как вы никогда не позволяете циклу обработки событий в текущем потоке, и именно цикл обработки событий уничтожает их.

Нет причин создавать файловый объект в куче, и нет никаких причин явно закрывать файл: QFile является правильным классом C++, который реализует RAII. Уничтожить его безопасно в любом состоянии, без утечек ресурсов. Просто уничтожьте файл, чтобы закрыть его основной дескриптор.

Включая вышеупомянутые предложения, код должен быть:

for (;;){
   QFile file("some.txt");
   if (file.exists()){
      file.open(QFile::ReadOnly);
      auto contents = file->readAll();
      qDebug() << "read, n=" << contents.size();
   }
   QThread::sleep(2);
}

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

auto timer = new QTimer;
timer->start(2000);
auto reader = []{
  QFile file("some.txt");
  if (file.exists()){
    file.open(QFile::ReadOnly);
    auto contents = file->readAll();
    qDebug() << "read, n=" << contents.size();
  }
});
connect(timer, &QTimer::timeout, reader);

Чтобы закончить чтение, остановите или уничтожьте таймер.

Поток должен вращать цикл событий - и реализация по умолчанию QThread::run сделаю это для вас. Таким образом, приведенный выше код может быть заключен в QObject и перенесен в специальный поток, который также должен использоваться для других целей.

В качестве альтернативы, вы можете использовать пул потоков и выполнять чтение в рабочем потоке, но запустить таймер в потоке графического интерфейса. Только connect приведенное выше утверждение необходимо изменить на:

connect(timer, &QTimer::timeout, [reader]{ QtConcurrent::run(reader); });
Другие вопросы по тегам