LINUX.ORG.RU

Как прервать открытия файла в Qt?

 , , ,


0

2

Здравствуйте! Разрабатываю ПО для Windows и Linux и столкнулся с проблемой, что если в windows QFile-ом открыть удаленный файл(если доступа нет), то открывается он очень долго(секунд 15) и в конце концов возвращает false, в Linux аналогично.

Код функции примерно таков:


void function(const& QString filename, const& QString secondFilename)
{
    QFile file(filename); // пример windows: filename="//192.168.0.1/folder/file.txt
                          // пример linux: filename="/mnt/192.168.0.1/file.txt(монтирую сразу на папку folder)
    if (file.open()) { // На этом моменте и зависает...(если доступа по локалке нет)
       doSomeWork();
    } else {
      QFile reserveFile(secondFilename); // Если файл с первым именем не открылся, пробуем открыть резервный файл(тоже лежащий удаленно). Прим: //192.168.1.1/folder/file.txt или аналогично для линуксы
      if (reserveFile.open()) { // Здесь тоже есть возможность зависания
           doSomeWork();
      }
      reserveFile.close();
    }
    file.close();
}

Выводил в отдельный поток при этом ожидая в основном потоке 500 мс через QThread::msleep(500); потом убивал поток через QThread::terminate() и делал QThread::wait() но ожидание тоже долгое. Иногда даже дольше чем открывать файл.

Подскажите как верно реализовать отмену функции открытия файла( и не дожидаться окончания её работы ) если прошел некоторый timeout предположим в 500 мс?

QThread::terminate()

Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.

Ты уверен, что все правильно делаешь?

NickNotNick
()
Ответ на: комментарий от kostik87

К сожалению тоже зависает… :( (проверял на винде)

void MainWindow::on_btnTest_clicked()
{
   QFile file("\\\\192.168.0.1\\folder\\file.txt");
   qDebug() << file.exists(); // На этом моменте зависание
}

Сделал маленькое приложение, к сожалению зависает :(

Nikci12
() автор топика

Не надо так делать. Эта задержка - ответственность ОС, а не приложения, и не надо в приложение пихать костыли к ОС, тем более такие грубые. Настраивай или фикси ОС (возможно, ядро).

firkax ★★★★★
()

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

NickNotNick
()
Ответ на: комментарий от zurg

А можно простой примерчик как это можно сделать?

Как мне в отдельном процессе проверять наличие/отсутствие файла и потом вернуть наименование файла(к которому удалось подключиться) в основной процесс?

Nikci12
() автор топика
Ответ на: комментарий от Nikci12

самое простое через каналы https://doc.qt.io/qt-6/qprocess.html#communicating-via-channels, дочерний процесс просто пишет/читает в стандартный ввод/вывод, вообще вариант с отдельным процессом выглядит несколько оверхедно: это если надо часто и в фоновом режиме такие файлы открывать и мы никак не можем влиять на настройки сетевых файловых систем, сначала лучше попробовать примерно как здесь написали Как прервать открытия файла в Qt? (комментарий)

zurg
()
Последнее исправление: zurg (всего исправлений: 1)

Никак, сетевые ресурсы в винде очень медленные когда они не доступны - легко может explorer.exe подвиснуть если у него накапливается очередь задач по недоступным сетевым - приходится его перезапускать, там тупо большие таймауты. Очевидно надо дать потоку нормально завершиться. Так что делай quit(), а ждать завершения не надо - deleteLater().

anonymous
()

убивал поток через QThread::terminate() и делал QThread::wait() но ожидание тоже долгое

void QThread::setTerminationEnabled(bool enabled = true) Enables or disables termination of the current thread based on the enabled parameter. The thread must have been started by QThread.

When enabled is false, termination is disabled. Future calls to QThread::terminate() will return immediately without effect. Instead, the termination is deferred until termination is enabled.

anonymous
()

Подскажите как верно реализовать отмену функции открытия файла( и не дожидаться окончания её работы

Welcome to the real world. А по делу: как правильно реагировать на timeout на open() - конечно Вам никто не скажет (или я проблему неправильно понимаю). Это то решение которое Вам принять нужно.

bugfixer ★★★★★
()
Ответ на: комментарий от Nikci12

Можно попросить код решения?

Не могу обещать – сейчас очень мало свободного времени. Может быть тебе имеет смысл выложить проблемный код? Кто-нибудь да подскажет решение.

NickNotNick
()

man 2 open

TLDR: O_NONBLOCK

If O_NONBLOCK is set, the open() function shall return without blocking for the device to be ready or available. Subsequent behavior of the device is device-specific. If O_NONBLOCK is clear, the open() function shall block the calling thread until the device is ready or available before returning

Надеюсь в Qt есть обёртка над этим флагом. Удачи!

realbarmaley ★★
()
Ответ на: комментарий от realbarmaley

Кстати, интересный вопрос… Я предполагаю, что можно было бы в отдельном потоке делать не библиотечный вызов qfile, а системный вызов open. Его, наверное, можно прервать с помощью уничтожения потока.

realbarmaley ★★
()
Ответ на: комментарий от NickNotNick

Ребят! Спасибо всем большое. Я просто создал новый объект унаследованный от QObject(CheckFileExistance), реализовал в нем метод process() и обменивался сигналами.

У меня был глобальный объект(который живет на протяжении всего времени) и я засунул туда указатель на QThread и указатель на CheckFileExistance. А создавал тред, только когда вызывал эту функцию и забрасывал в отдельный поток класс CheckFileExistance

Очень помог совет, забить на ожидание и крутить его в потоке, пока не завершится, а не пытаться убить насильно terminate()-ом, или quit()-ом, все равно поток будет висеть какое-то время. Понял, что в винде и линуксе разный таймаут на ожидание сети при получении файла. Благодарен :)

void CheckFileExistance::process()
{
    QFile file(m_filename);
    m_lastThreadMessage = CheckFileThreadMessage{m_filename, TRY_OPEN};
    /* Посылаем сигнал о попытке открыть файл m_filename */
    emit processingMessage(m_lastThreadMessage);
    if (file.exists()) {
        m_lastThreadMessage = CheckFileThreadMessage{m_filename, OPENED};
        emit processingMessage(m_lastThreadMessage);
    } else {
        /* Проверка если нужно завершать поток */
        if (QThread::currentThread()->isInterruptionRequested()) {
            emit finished();
            return;
        }
        file.setFileName(m_reserveFilename);
        m_lastThreadMessage = CheckFileThreadMessage{m_reserveFilename, TRY_OPEN};
        emit processingMessage(m_lastThreadMessage);
        if (file.exists()) {
            m_lastThreadMessage = CheckFileThreadMessage{m_reserveFilename, RESERVE_FILE_OPENED};
            /* Меняем имя основного файла на резервный */
            qSwap(m_filename, m_reserveFilename);
            emit processingMessage(m_lastThreadMessage);
        } else {
            m_lastThreadMessage = CheckFileThreadMessage{m_reserveFilename, FAILED};
            emit processingMessage(m_lastThreadMessage);
        }
    }
    emit finished();
}

Nikci12
() автор топика