2012-06-07 6 views
0

У меня есть приложение Qt, которое запускает два потока из основного потока при запуске. Оба этих потока выполняют сетевые запросы, используя различные экземпляры объекта QNetworkAccessManager. Моя программа продолжает сбой примерно в 50% случаев, и я не уверен, какой поток сбой.Ошибка приложения Qt при выполнении 2 сетевых запросов из 2 потоков

Передача данных или передача сигналов между двумя потоками отсутствует. Когда происходит определенное событие, один поток сигнализирует основной поток, который может в свою очередь сигнализировать второй поток. Однако, печатая журналы, я вполне уверен, что авария не происходит во время сигнализации.

Структура обеих нитей следующая. Там вряд ли какая-то разница между нитями для URL, кроме т.д.

MyThread() : QThread() { 
    moveToThread(this); 
} 

MyThread()::~MyThread() { 
    delete m_manager; 
    delete m_request; 
} 

MyThread::run() { 
    m_manager = new QNetworkAccessManager(); 
    m_request = new QNetworkRequest(QUrl("...")); 

    makeRequest(); 
    exec(); 
} 

MyThread::makeRequest() { 
    m_reply = m_manager->get(*m_request); 
    connect(m_reply, SIGNAL(finished()), this, SLOT(processReply())); 
    // my log line 
} 

MyThread::processReply() { 
    if (!m_reply->error()) { 
     QString data = QString(m_reply->readAll()); 
     emit signalToMainThread(data); 
    } 
    m_reply->deleteLater(); 
    exit(0); 
} 

Теперь странная вещь, что если я не начать один из потоков, программа работает нормально, или, по крайней мере, не врезаться в около 20 приглашений. Если оба потока выполняются один за другим, программа не сбой. Программа запускает только в половине случаев, если я запускаю и запускаю оба потока одновременно.

Еще одна интересная вещь, которую я собрал из журналов, заключается в том, что всякий раз, когда программа выходит из строя, строка, помеченная комментарием my log line, является последней, которая будет выполняться обоими потоками. Поэтому я не знаю, какой поток вызывает крах. Но это заставляет меня подозревать, что QNetworkAccessManager как-то виноват.

Я довольно пуст о том, что вызывает крушение. Буду признателен за любые предложения или указатели. Заранее спасибо.

ответ

0

Прежде всего you're doing it wrong! Сначала закрепите резьбу

// EDIT Из моего собственного опыта с этим рисунком я знаю, что это может привести ко многим неясным авариям. Я начну с очистки этой вещи, так как это может выправить некоторые вещи и сделать поиск проблемы ясными. Также я не знаю, как вы вызываете makeRequest. Также о QNetworkRequest. Это только структура данных, поэтому вам не нужно делать ее на куче. Сложной конструкции было бы достаточно. Также вы должны помнить (или защищать как-то) от перезаписи указателя m_reply. Вы звоните makeRequest несколько раз? Если вы это сделаете, это может привести к удалению текущего обработанного запроса после завершения предыдущего запроса.

Что произойдет, если вы звоните makeRequest дважды:

  1. Первый вызов makeRequest назначает m_reply указатель.
  2. Второй вызов makeRequest назначает второй раз указатель m_reply (заменяет назначенный указатель, но не удаляет заостренный объект)
  3. Второй запрос заканчивается перед первым, поэтому вызывается processReply. deleteLater ставится в очередь на второй
  4. Где-то в eventloop второй ответ удаляется, поэтому теперь m_reply указатель указывает на некоторую случайную (удаленную) память.
  5. Первый ответ завершается, поэтому вызывается другой processReply, но он работает на m_reply, который указывает мусор, поэтому каждый вызов в m_reply вызывает сбой.

Это один из возможных сценариев. Вот почему вы не получаете аварии каждый раз.

Я не уверен, почему вы называете exit (0) при завершении ответа. Здесь также неверно, если вы используете более одного вызова makeRequest. Помните, что QThread является интерфейсом для одного потока, а не для пула потоков. Поэтому вы не можете позвонить start() во второй раз на экземпляр потока, когда он все еще запущен. Также, если вы создаете диспетчер сетевого доступа в точке входа run(), вы должны удалить его в том же месте после exec(). Помните, что exec() блокирует, поэтому ваши объекты не будут удалены до выхода вашего потока.

+0

Я столкнулся с двумя сообщениями (неправильный путь и правильный путь) довольно поздно в разработке приложения. Мой Java-фон тоже не помог, где вы обычно расширяете Thread для потоковой обработки. Независимо от того, что проблема связана с самим диспетчером сетевого доступа, а не с потоком. Я попробую данный подход с фрагментом кода, который воспроизводит проблему. Пожалуйста, дайте свои данные о любых нюансах QNetworkAccessManager, которые могут отсутствовать. Благодарю. – Sameer

+0

См. Мой отредактированный ответ –

+0

И еще одно редактирование –

 Смежные вопросы

  • Нет связанных вопросов^_^