Новый 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); });