#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
он уже асинхронный (так сказано в документах).