2012-06-11 5 views
1

Я пытаюсь загрузить веб-страницу с помощью QNetworkAccessManager :: get() с отдельным потоком. Когда я запускаю программу, она будет разбиваться случайным образом (может быть один час или два часа). Пример кода:QNetworkAccessManager :: get() вызывают чистый виртуальный метод под названием

class SpiderThread : public QThread 
{ 
    Q_OBJECT 
public: 
    SpiderThread(); 
    void run(); 
private: 
    bool _stopped; 
}; 

void SpiderThread::run() 
{ 
    while (!_stopped) { 
     DownloadManager downloadManager(); 
     QUrl u = getOneUrl(); 
     QString content = downloadManager.getContent(u); 
     // some other code 
    } 
} 


QString DownloadManager::getContent(const QUrl &url) 
{ 
    QEventLoop loop; 
    QNetworkAccessManager manager; 

    QNetworkRequest request(url); 
    request.setRawHeader("User-Agent", _userAgent.toAscii()); 
    QNetworkReply *reply = manager.get(request); 
    connect(reply, SIGNAL(finished()), 
      SLOT(replyFinished())); 
    connect(reply, SIGNAL(finished()), 
      &loop, SLOT(quit())); 

    loop.exec(); 
    if (reply->error() != QNetworkReply::NoError) { 
     if (reply->isRunning()) 
      reply->abort(); 
     reply->deleteLater(); 
     return QString(); 
    } 


    int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 

    if (httpCode != 200) 
     return QString(); 
    QByteArray data = reply->readAll(); 
    reply->deleteLater(); 
    return QString(data); 
} 

Я использую QEventLoop блокировать запрос HTTP, пока не Finshed, когда я бегу эти кода, это всегда сбой и сообщение показать сообщение об ошибке:

 
    pure virtual method called 
    terminate called without an active exception 

инфо GDB отладки :

 
    (gdb) bt 
    #0 0x0000003c0dc30285 in raise() from /lib64/libc.so.6 
    #1 0x0000003c0dc31d30 in abort() from /lib64/libc.so.6 
    #2 0x0000003d992bed94 in __gnu_cxx::__verbose_terminate_handler()() from /usr/lib64/libstdc++.so.6 
    #3 0x0000003d992bce46 in ??() from /usr/lib64/libstdc++.so.6 
    #4 0x0000003d992bce73 in std::terminate()() from /usr/lib64/libstdc++.so.6 
    #5 0x0000003d992bd3cf in __cxa_pure_virtual() from /usr/lib64/libstdc++.so.6 
    #6 0x00002aaaabc3cc35 in QCoreApplication::postEvent(QObject*, QEvent*, int)() 
      from /usr/local/Trolltech/Qt-4.8.2/lib/libQtCore.so.4 
    #7 0x00002aaaabc5301d in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() 
      from /usr/local/Trolltech/Qt-4.8.2/lib/libQtCore.so.4 
    #8 0x00002aaaab7b81a1 in ??() from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #9 0x00002aaaab7ac3ad in ??() from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #10 0x00002aaaab7c8d1d in ??() from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #11 0x00002aaaab7cadb0 in ??() from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #12 0x00002aaaab7a89ce in QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation, QNetworkRequest const&, QIODevice*)    () 
      from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #13 0x00002aaaab7a5ea4 in QNetworkAccessManager::get(QNetworkRequest const&)() 
        from /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4 
    #14 0x00000000004088fe in DownloadManager::getContent (this=0x409fff40, url=..., toCodec=...) 
         at src/downloadmanager.cpp:55 
    #15 0x0000000000415248 in SpiderThread::run (this=0x7fffffffe2b0) at src/spiderthread.cpp:27 
    #16 0x00002aaaabb2c3b9 in ??() from /usr/local/Trolltech/Qt-4.8.2/lib/libQtCore.so.4 
    #17 0x0000003c0e40677d in start_thread() from /lib64/libpthread.so.0 
    #18 0x0000003c0dcd325d in clone() from /lib64/libc.so.6 

Пожалуйста, помогите мне, я провел так много времени, чтобы найти то, что это неправильно, но это еще не work.I сделал какую-то ошибку?

+0

Попробуйте создать 'QNetworkAccessManager' в куче, некоторые объекты Qt плохо себя ведут в стеке. Также, как указано в документах: «Один QNetworkAccessManager должен быть достаточным для всего приложения Qt». Кажется, вы создаете короткоживущий для каждого запроса, который, возможно, не помогает. – cmannett85

+0

Благодарим вас за предложение. Я пытаюсь создать QNetworkAccessManager в куче, но он все еще не работает. Один QNetworkAccessManager имеет «6 запросов, выполняемых параллельно для одной комбинации хостов и портов». Этого недостаточно для моего проекта. Поэтому я хочу создать более одного объекта QNetworkAccessManager. – Linuxsong

+0

Привет, Я сталкиваюсь с той же проблемой. Вы нашли решение? – SaiyanRiku

ответ

2

Вы бесполезно усложнили ситуацию. По умолчанию реализация QThread::run() уже создает и запускает цикл событий. Не извлекайте из QThread. Поместите свою функциональность в QObject и вызовите moveToThread(thread) на этом объекте после того, как вы запустили поток, при необходимости! Используйте сигналы и слоты, чтобы все было сделано. QNetworkAccessManager уже использует рабочий поток IIRC, поэтому, вероятно, бессмысленно создавать его в еще одном выделенном потоке.

+0

Спасибо @KubaOber. Я не знаю, что QThread может использовать как это раньше. Но вывод из QThread должен работать, я не знаю, почему мой код имеет crash.I будет пытаться использовать сигналы и слоты, чтобы все было сделано. – Linuxsong

+0

Вам необходимо отправить полный код. Уменьшите ненужные части, которые порог воспроизводит проблему. Вы можете понять это сами, пока вы это делаете. Опять же, нет необходимости создавать другой поток, пока вы не профилируете свое приложение и не увидите, что он связан с CPU (привязывает одно ядро ​​процессора на 100%). –