Russian Qt Forum

Qt => Работа с сетью => Тема начата: BloodyTux от Октябрь 23, 2010, 19:24



Название: QNetworkAccessManager & QThreads
Отправлено: BloodyTux от Октябрь 23, 2010, 19:24
Доброго времени суток!

Мне необходимо сделать многопоточное приложение, отправляющее http запросы. Естественно логично было бы использовать QNetworkAccessManager, но вот незадача:  когда запускаю в одном потоке, работает стабильно, при большем количестве - вылетают ошибки связанные с QMutex::lock(). Код:
Код:


/ ************** main.cpp **************** /


#include <QtCore/QCoreApplication>
#include <QDebug>
#include "threadhttpdownload.h"

#define USAGE QT_TRANSLATE_NOOP("threadDownload::main", "usage: %s <link> <file name>")

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        qDebug(USAGE, argv[0]);
        return 0;
    }

    QCoreApplication a(argc, argv);

    for (int i = 0; i < 5; i++) {
        ThreadHttpDownload *th = new ThreadHttpDownload(0,argv[1]);
        th->start();
        qDebug() << "tread " << i << " started";

    }

    return a.exec();
}



/ ************** threadhttpdownload.h **************** /



#ifndef THREADHTTPDOWNLOAD_H
#define THREADHTTPDOWNLOAD_H

#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QFile>
#include <QDebug>

class ThreadHttpDownload : public QThread
{
    Q_OBJECT

    public:
        ThreadHttpDownload(QObject *parent,QString link);

        void run();

    private:

        QString link;

    private slots:
        void replyFinished(QNetworkReply*);
};

#endif // THREADHTTPDOWNLOAD_H



/ ************** threadhttpdownload.h **************** /



#include "threadhttpdownload.h"

ThreadHttpDownload::ThreadHttpDownload(QObject *parent,QString _link)
        :QThread(parent)
{
     link = _link;

}

void ThreadHttpDownload::run()
{
   // qDebug() << currentThreadId();

    QNetworkAccessManager manager;

    connect(&manager, SIGNAL(finished(QNetworkReply*)),
             this, SLOT(replyFinished(QNetworkReply*)), Qt::DirectConnection);

    manager.get(QNetworkRequest(QUrl(link)));

    exec();
}


void ThreadHttpDownload::replyFinished(QNetworkReply *reply)
{
    // qDebug() << currentThreadId();

    if (reply->error())
    {
        qDebug() << "error download" << reply->errorString();
    }else
    {
        reply->readAll();
        qDebug() << "download complete";
    }
}


Варианты вывода :
Цитировать
tread  0  started
tread  1  started
tread  2  started
tread  3  started
tread  4  started
QMutex::lock: mutex lock failure: Недопустимый аргумент
download complete
download complete
download complete
download complete
download complete

Цитировать
tread  0  started
tread  1  started
tread  2  started
tread  3  started
tread  4  started
Ошибка сегментирования


replyFinished(QNetworkReply *reply) выполняется в рабочем потоке - проверял. Не могу понять, в чем дело... Да, проблема возникает и на linux и на win. QTcpSocket конечно работает, но как-то не хочется иметь дело с примитивами. :)


Название: Re: QNetworkAccessManager & QThreads
Отправлено: GNU Dimarik от Октябрь 24, 2010, 17:48
Я вообще не понял в чем проблема... Давайте сюда код с мютексами.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: BloodyTux от Октябрь 25, 2010, 17:11
Все, спасибо. Решил проблему.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: ufna от Октябрь 25, 2010, 20:47
А в чем была проблема?


Название: Re: QNetworkAccessManager & QThreads
Отправлено: AlekseyK от Октябрь 26, 2010, 01:26
Все, спасибо. Решил проблему.
Обычно люди помещают решение и код, если проблема решена, чтобы тем, кто идёт следом было полегче.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: BloodyTux от Октябрь 26, 2010, 17:14
Дело в том, что решение, так сказать, радикальное. Решил отказаться от Qt для разработки данного проекта. :)


Название: Re: QNetworkAccessManager & QThreads
Отправлено: Авварон от Октябрь 26, 2010, 17:39
Мда... Вообще стоило сначала почитать про thread-safety и reentrant:)


Название: Re: QNetworkAccessManager & QThreads
Отправлено: Sahab от Октябрь 27, 2010, 09:40
на сокетах Беркли решил написать?))


Название: Re: QNetworkAccessManager & QThreads
Отправлено: AlekseyK от Октябрь 27, 2010, 12:03
Мда... Вообще стоило сначала почитать про thread-safety и reentrant:)
Я вот почитал - мне не помогло, у меня схожая проблема: http://www.prog.org.ru/topic_15421_0.html


Название: Re: QNetworkAccessManager & QThreads
Отправлено: ufna от Октябрь 27, 2010, 12:35
Я сделал у себя немного по-другому, главное отличие касается run() функции, т.к. там есть "непонятки" с потоком-родителем и т.п.

привожу код, я его использую для многопоточной загрузки файлов на сервак по частям. Это урезанная версия для выкладки, поэтому может сходу не работать, но суть по коду ясна где что добавить/изменить для ваших целей.

подрихтовал и опубликовал здесь: http://ufna.ru/2010/10/27/qt-qnetworkaccessmanager-multithread


Название: Re: QNetworkAccessManager & QThreads
Отправлено: AlekseyK от Октябрь 27, 2010, 12:43
Честно говоря не понял, что нужно изменить: у меня по принципу код похожий. Но ошибка вываливается, только, если закрыть программу во время загрузки страницы. Если позже - ошибка не возникает. Может QByteArray долго передаётся - не знаю (не понятно):
Код
C++ (Qt)
141: emit pageContentReady(pageContent, pageAddress);


Название: Re: QNetworkAccessManager & QThreads
Отправлено: ufna от Октябрь 27, 2010, 13:43
он падает в любой момент при закрытии лично у меня

ошибка скорее всего в том, что менеджеру кто-то после этого шлет сигналы, а его уже нет. Суровое удаление через delete тут рисованно.

я бы на твоем месте сделал просто manager->setParent(this); после того как заслал его в this поток.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: AlekseyK от Октябрь 27, 2010, 14:11
Да, успешно, работает, спасибо. Теперь проверить нет ли утечек памяти.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: ufna от Октябрь 27, 2010, 14:18
"По идее" - быть не должно, поток-родитель подтереть должен. На практике - класс умирает вместе с приложением, висеть ничего не остается, потому в любом случае не критично.


Название: Re: QNetworkAccessManager & QThreads
Отправлено: AlekseyK от Октябрь 27, 2010, 14:33
По идее - да, пробежался valgrind-ом на всякий случай - в этом компоненте их нет. Огромное спасибо!!!


Название: Re: QNetworkAccessManager & QThreads
Отправлено: ufna от Октябрь 27, 2010, 14:48
не за что ;)


Название: Re: QNetworkAccessManager & QThreads
Отправлено: BloodyTux от Октябрь 27, 2010, 17:40
Спасибо, ufna, за решение!! К сожалению, мне оно уже не пригодится, но тема была явно не зря создана. :D