QNetworkAccessManager из ThreadPool

#multithreading #qt #threadpool #runnable #qnetworkaccessmanager

#многопоточность #qt #пул потоков #работоспособный #qnetworkaccessmanager

Вопрос:

Очень фундаментальный вопрос. В документации упоминается, что все методы в QNetworkAccessManager являются реентерабельными. Если да, является ли выполнение get() метода в QRunnable без блокировок законным? Мой код выглядел бы примерно так:

 class MyClass: public QRunnable
{
    void run()
    {
        ...
        QNetworkAccessManager nam;
        QNetworkReply* reply =  name.get(request)    // No Read-write lock.
        ...
    }
};
  

Ответ №1:

Из документации Qt:

[…] класс называется реентерабельным, если его функции-члены могут [одновременно] безопасно вызываться из нескольких потоков, при условии, что каждый поток использует другой экземпляр класса.

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

Комментарии:

1. Если бы у меня был экземпляр QNetworkAccessManager, общий для разных потоков, был бы вызов get по-прежнему действителен из разных потоков ?? т.Е. если экземпляр QNetworkAccessManager передается QRunnable во время его создания и его метод get вызывается в run (), как я упоминал выше, все равно не возникло бы проблем??

2. @de costa: нет, это привело бы к сбою. Вам понадобится QMutex для сериализации доступа к нему, но : QNetworkAccessManager является QObject и поэтому его необходимо moveToThread() отредактировать, чтобы безопасно вызывать его, даже с защитой от мьютексов (обработчики событий могут быть вызваны на QObject s практически в любое время). Поскольку QRunnable ы выполняются в потоке, который вы не можете предсказать извне QThreadPool , и moveToThread() могут только передавать объект в, а не извлекать из другого потока, вы не можете использовать QObject их в QRunnable объектах, которые там не были созданы (если вы не синхронизируете их внутренне, т. Е. не делаете потокобезопасными).

3. В таком случае, насколько дорого было бы создать QNetworkAccessManager для каждого отдельного QRunnable внутри ThreadPool?? Считается ли это хорошей практикой?? Другой альтернативной, но потенциально неустранимой реализацией является наличие QObject в моем QRunnable и реализация обмена сигналами / слотами с QNetworkAccessManager, экземпляр которого был создан в потоке, создавшем QThreadPool. Есть предложения??

4. @de costo: Это то, что вы уже делаете в OP. Что касается стоимости: QNetworkAccessManager по сути, это параметризуемая фабрика (как на абстрактной фабрике). Если вам не нужна параметризуемость (например, вы не хотите расширять ее дополнительными поддерживаемыми протоколами), ее создание на месте должно потребовать минимальных затрат. Если вы не можете использовать его таким образом по той или иной причине, просто используйте его в основном потоке, что является немного более идиоматичным способом. QNetworkReply s являются QIODevices и поддерживают асинхронную работу, например, с readyRead() сигналом, поэтому вам не нужны потоки (загрузка связана с вводом-выводом).

5. @Marc Mutz: если мы используем более одного QNetworkAccessManager , сложно установить настройки кэша и прокси для всех из них.

Ответ №2:

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