1

別のスレッドでQNetworkAccessManager::get()を使用してWebページをダウンロードしようとしています。プログラムを実行すると、ランダムにクラッシュします(1時間または2時間の場合があります)。コード例:

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リクエストが終了するまでブロックしています。これらのコードを実行すると、常にクラッシュしてエラーメッセージが表示されます。

    と呼ばれる純粋仮想メソッド
    アクティブな例外なしで呼び出された終了

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 ?? ()/usr/lib64/libstdc++.so.6から
    #4 0x0000003d992bce73 in std :: terminate()()from /usr/lib64/libstdc++.so.6
    #5 /usr/lib64/libstdc++.so.6の__cxa_pure_virtual()の0x0000003d992bd3cf
    #6 0x00002aaaabc3cc35 in QCoreApplication :: postEvent(QObject *、QEvent *、int)()
           /usr/local/Trolltech/Qt-4.8.2/lib/libQtCore.so.4から
    #7 0x00002aaaabc5301d in QMetaObject :: activate(QObject *、QMetaObject const *、int、void **)()
           /usr/local/Trolltech/Qt-4.8.2/lib/libQtCore.so.4から
    #8 0x00002aaaab7b81a1 in ?? ()/usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #9 0x00002aaaab7ac3ad in ?? ()/usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #10 0x00002aaaab7c8d1d in ?? ()/usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #11 0x00002aaaab7cadb0 in ?? ()/usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #12 0x00002aaaab7a89ce in QNetworkAccessManager :: createRequest(QNetworkAccessManager :: Operation、QNetworkRequest const&、QIODevice *)()
          /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #13 0x00002aaaab7a5ea4 in QNetworkAccessManager :: get(QNetworkRequest const&)()
                     /usr/local/Trolltech/Qt-4.8.2/lib/libQtNetwork.so.4から
    #14 DownloadManager :: getContentの0x00000000004088fe(this = 0x409fff40、url = ...、toCodec = ...)
                         src / downloadmanager.cpp:55で
    #15 0x0000000000415248 in SpiderThread :: run(this = 0x7fffffffe2b0)at src / spiderthread.cpp:27
    #16 0x00002aaaabb2c3b9 in ?? ()/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

助けてください、私は何が悪いのかを見つけるのに多くの時間を費やしましたが、それでもうまくいきません。私はいくつかの間違いをしましたか?

4

1 に答える 1

2

あなたは不必要に複雑なことをしました。のデフォルトの実装は、QThread::run()すでにイベントループを作成して実行しています。QThreadから派生しないでください。機能をQObjectに入れ、必要moveToThread(thread)に応じて、スレッドを開始したらそのオブジェクトを呼び出します。信号とスロットを使用して物事を成し遂げます。QNetworkAccessManagerはすでにワーカースレッドIIRCを使用しているため、さらに別の専用スレッドで作成しても意味がありません。

于 2012-06-11T16:14:05.063 に答える