2012-04-17 3 views
13

Имейте приложение, в котором у меня есть QOBJects, все из которых содержат QNetworkAccessManager. Я знаю, что это предлагается только для каждого приложения, но поскольку я делаю гораздо больше, чем 6 звонков одновременно, мне нужно было это сделать так. Итак, вот как я начинаю темы.Количество потоков увеличивается, даже при удалении потоков

FileUploader *fileUploader = new FileUploader(_fileList); 
QThread *fileUploaderThread = new QThread(); 
fileUploader->moveToThread(fileUploaderThread); 

// uploader > model 
connect(fileUploader, SIGNAL(progressChangedAt(int)), _model, SLOT(reportProgressChanged(int)), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(statusChangedAt(int)), _model, SLOT(reportStatusChanged(int)), Qt::QueuedConnection); 
// uploader > its thread 
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finishedCurrentUpload()), this, SLOT(uploadNextFileOrFinish()), Qt::QueuedConnection); 
// thread > this 
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(checkIfAllThreadsAreFinished()), Qt::QueuedConnection); 
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(deleteFinishedThread()), Qt::QueuedConnection); 
// this > uploader 
connect(this, SIGNAL(cancel()), fileUploader, SLOT(cancel()), Qt::QueuedConnection); 

fileUploaderThread->start(); 
QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection); 
QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex)); 

QMutexLocker locker(&_mutex); 
_threadCount++; 

Каждый поток начинается с индекса в списке, таким образом, что они могут принести, что им нужно, чтобы загрузить и продолжить около 5 шагов (звонки с QNetworkAccessManager). Когда нет больше нет элементов для загрузки, то fileUploader сигналы «закончил()», который вызывает deleteFinishedThread и deleteFinishedUploader, где я делаю:

QThread *thread = qobject_cast<QThread*>(sender()); 

if(thread != NULL) thread->deleteLater(); 

или

FileUploader *fileUploader = qobject_cast<FileUploader*>(sender()); 

if(fileUploader != NULL) fileUploader->deleteLater(); 

Они предполагают, чтобы удалить нити, когда они сделано.

Проблема в том, что каждый раз, когда я запускаю (например) 3 потока, которые имеют 1 файл для загрузки и обработки каждого, количество потоков увеличивается на 8-10. Это означает, что количество потоков составляет от 5 до 100, если несколько раз перезагрузите процесс загрузки.

Что я делаю неправильно? Или моя самая большая проблема, которую я использую «Диспетчер задач Windows», чтобы контролировать это? Я обрабатываю все ответы от QNAM, которые я удаляю, и все, кажется, удаляется, но все же я почесываю голову, когда количество строк продолжает увеличиваться ...

EDIT: В моем файловом загрузчике я создаю объект (Менеджер) на куча, которая имеет кластер QNetworkAccessManager в стеке. Когда файловый загрузчик удаляется, он вызывает «deleteLater()» в Менеджере, но он никогда не удаляется. Мы попытались удалить Диспетчер и установить его в NULL, но это дало нам нарушение доступа, так как Менеджер еще не был выполнен (QNetwork.dll сообщила об ошибке, так что это должно быть что-то внутри QNAM, который все еще работает). Время, когда мы не получили нарушение доступа, объект был удален, и количество потоков вернулось к нормальному состоянию. Что может жить внутри QNAM и мешать мне удалять его, когда он выходит за рамки? Должен ли я создать QNAM вместо кучи? На этом этапе не деструкторы вызываются даже при вызове метода deleteLater() ...

Также, как уменьшить количество элементов управления?

+1

добавил щедрость. на ваш вопрос нужна какая-то любовь ... – UmNyobe

+0

ой, спасибо. вы сделали свой день :) – chikuba

+0

один комментарий: если вы все еще используете их, вызовите 'QMetaObject :: invokeMethod (' перед запуском 'fileUploaderThread'. Это лучший способ обеспечить, чтобы эти слоты вызывались при первом запуске цикла потока. – UmNyobe

ответ

1

После многих «почти сдающихся» я придумал решение для потоков. Это правда, что Synxis сказал о порядке слотов.

У меня все же есть проблема с файловыми дескрипторами, и если у кого-то есть лучший ответ, я, мой рад принять это.

Я изменил мой код:

... 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
// uploader > its thread 
connect(fileUploader, SIGNAL(destroyed()), fileUploaderThread, SLOT(quit())); 

Это означает, что поток получает остановлен (бросить курить()), когда объект становится удален. Это действительно работает, даже если в документации указано:

Этот сигнал излучается непосредственно перед уничтожением объекта obj и не может быть заблокирован.

Все дети объекта уничтожаются сразу же после того, как этот сигнал испускается.

Это означает, что эти сигналы испускаются только до того, как что-либо разрушается (что означало бы, что я прекратил бы нить до того, как вы удалили загрузчик)? Не очень хорошо, и это может быть лучше. ОДНАКО, atm, количество моих потоков уменьшается с каждым раз, когда загрузчик заканчивается и возвращается в нормальное состояние после 20 секунд или около того (несколько «потоков наблюдателей» должны быть убиты окнами и т. Д.).

+0

Хорошее решение для слотов. Как обрабатываются/создаются/удаляются файлы? В чем проблема с ними? – Synxis

+0

Я не уверен. имеют некоторый опыт работы с C# и как вы это делаете, но теперь я могу видеть, что количество ручек увеличивается, но не уменьшается – chikuba

+0

. Проблема в том, что я не уверен, удаляет ли поток до того, как объекты внутри него будут уничтожены .. – chikuba

7

Я могу ошибаться, но я думаю, что есть проблема с сигналами:

// uploader > its thread 
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 

Помните, что, когда несколько слотов подключены к тому же сигналу, они выполняются в порядке подключения. Здесь, когда fileUploader будет завершен, он вызовет finished(), который сначала вызовет метод потока quit(), а затем метод deleteFinishedUploader(). То же самое для сигнала canceled(). Но тем временем поток был закончен, поэтому обработка событий для файлового загрузчика не может быть выполнена (следствие moveToThread(...)). deleteLater() нуждается в обработке событий, поэтому ваш файловый загрузчик никогда не будет удален ...

Я не на 100%, что организация ваших соединений другим способом заставит работать: можно вызвать deleteLater(), и поток сразу же после, без обработка событий.

Решение может быть связано с загрузкой файла в основной поток или в поток, который по-прежнему обрабатывает цикл событий.

2

Не ответ, но:

fileUploaderThread->start(); 
    QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection); 
    QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex)); 

означает, что вы даже начать цикл, а затем очереди слоты или сигналы должны быть выполнены .. Предположим (в целом), что существуют и другие QObject в этой теме. Возможно, они получат свои слоты или сигналы, выполненные, потому что цикл событий уже запущен. Если вы хотите, чтобы «init» и «uploadAt» были первыми методами, вызываемыми при запуске цикла событий, вы ставите их в очередь перед запуском цикла событий (если поток не запущен, они никогда не будут выполняться).

От QMetaObject::invokeMethod:

Если тип Qt :: QueuedConnection, A QEvent будет послан и член вызывается, как только заявка входит в основной цикл событий.

В этом случае событие отправляется в цикл событий потока.

+0

О, ладно. действительно приятно знать спасибо! однако в этом примере я мог бы просто придерживаться того, что ive получил, поскольку загрузчик будет единственным элементом в этом потоке :) – chikuba

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

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