Название: QThread остановка потока без ошибки в QMutex или свой поисковик файлов
Отправлено: daimon от Марта 10, 2012, 17:10
C++ (Qt) #include "CFileFindThread.h" ///////////поток CFileFindThread::CFileFindThread( QObject*parent /*=0*/ ) :QThread(parent) { m_FilterNames.clear(); m_FilesList.clear(); m_Path.clear(); } CFileFindThread::CFileFindThread( QString path, QStringList fiterNames, QObject* parent/*=0*/ ) :QThread(parent) { m_Path = path; m_FilterNames =fiterNames; } QStringList CFileFindThread::getListFilesFind( const QString &pathr, QStringList filters ) { // m_processError = ETE_WAITFORMINGFILELIST; // QString path; if(pathr.isEmpty()) path = QDir::currentPath(); else path = pathr; QDir dir(path); if(!dir.exists()) { // emit isErrorDir(true); // // return QStringList(); } QStringList listFiles = QStringList(); foreach (QString file, dir.entryList(filters)) { listFiles << QFileInfo(dir, file).absoluteFilePath(); } int current=0; int all = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count(); foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { listFiles << getListFilesFind(path + QDir::separator() + subDir, filters); current ++; emit currentProgress(current *100 / all); } return listFiles; } void CFileFindThread::run() { QDir dir(m_Path); m_FilesList = getListFilesFind(m_Path,m_FilterNames); emit finished(m_FilesList); exec(); } //////////////// //////использую void startFind() { ui.listWidget->clear(); if(!m_threadFileFind) m_threadFileFind = new CFileFindThread(m_Path, m_FilterNames, this); connect(m_threadFileFind, SIGNAL(finished(QStringList)), this, SLOT(setFilesList(QStringList))); connect(m_threadFileFind,SIGNAL(currentProgress(int)),this,SLOT(setProgress(int))); connect(ui.pushButtonCancel, SIGNAL(clicked()),this ,SLOT(stopFind())); m_threadFileFind->start(); } public slots: void setFilesList(QStringList val) { m_FilesList = val; bool select = true; for(int i=0; i<val.count();i++) { QListWidgetItem * tempItem = new QListWidgetItem(val[i], ui.listWidget); tempItem->setCheckState(Qt::CheckState(2*select)); } m_isChangedContent = true; ui.groupBox_2->setVisible(true); delete m_threadFileFind; m_threadFileFind= NULL; emit finished(); } void stopFind() { ui.groupBox->setVisible(false); ui.groupBox_2->setVisible(true); m_threadFileFind->terminate(); delete m_threadFileFind; }
при таком использовании потока происходит ошибка (http://s2.ipicture.ru/uploads/20120310/ZohsVFRO.png) (http://s2.ipicture.ru/)
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: LisandreL от Марта 10, 2012, 18:54
1) exec() в вашем коде не нужен 2) terminate() опасен и может приводить к разнообразным ошибкам. Для прерывания используйте флаг который будете проверять периодически в getListFilesFind. + wait
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: lolbla2 от Марта 10, 2012, 19:14
оффтоп: Подскажите как Qt библиотеки в среду MSVS 2010 встроить?
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: LisandreL от Марта 10, 2012, 19:22
lolbla2, http://qt.nokia.com/downloads/visual-studio-add-in
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: daimon от Марта 11, 2012, 02:32
1) exec() в вашем коде не нужен 2) terminate() опасен и может приводить к разнообразным ошибкам. Для прерывания используйте флаг который будете проверять периодически в getListFilesFind. + wait
про флаг я тоже думал, но меня смущает рекурсия поиска файлов!!! и в каком месте совать проверку? пока решил ситуацию только локальным расположением потока, в функции startFind и понятное дело создал функцию, которая удаляет этот поток после сигнала (об завершении или разрушении) (вроде работает) но тут сразу получилась плохая ситуация - привязал кнопку на поток (критически завершать поток по клику) и поэтому только в функции startFind() есть сигнально-слотовая связка - всё работает и тут сразу возникает вопрос, а что делать если я захочу остановить поток извне (а он та локальный) - решение очень тупое, просто сгенерировать нажатие той клавиши останова в другой функции (слоте) этого же класса C++ (Qt) void CFileBrowser::startFind() { if(!m_isRunningFileFindThread) { ui.listWidget->clear(); CFileFindThread * threadFileFind = new CFileFindThread(m_Path, m_FilterNames, this); connect(threadFileFind,SIGNAL(finished(CFileFindThread*)),this,SLOT(deleteThread(CFileFindThread*))); connect(threadFileFind, SIGNAL(finished(QStringList)), this, SLOT(setFilesList(QStringList))); connect(threadFileFind,SIGNAL(currentProgress(int)),this,SLOT(setProgress(int))); connect(ui.pushButtonCancel, SIGNAL(clicked()),threadFileFind ,SLOT(emitStop())); if(!m_isRunningFileFindThread) connect(ui.pushButtonStart, SIGNAL(clicked()), this, SLOT(startFind())); threadFileFind->start(); m_isRunningFileFindThread = true; } } void CFileBrowser::deleteThread( CFileFindThread* val ) { if( val != NULL) { val->terminate(); val->deleteLater(); m_isRunningFileFindThread = false; } } void CFileBrowser::emitCancel() { if(m_isRunningFileFindThread) { qDebug()<<"auto click cancel"; ui.pushButtonCancel->click(); } } void CFileBrowser::setFilesList( QStringList val ) { m_FilesList = val; bool select = true; for(int i=0; i<val.count();i++) { QListWidgetItem * tempItem = new QListWidgetItem(val[i], ui.listWidget); tempItem->setCheckState(Qt::CheckState(2*select)); } m_isRunningFileFindThread = false; emit finished(); } //////////// void CFileFindThread::run() { qDebug()<<"start"<<this; QDir dir(m_Path); m_FilesList = getListFilesFind(m_Path,m_FilterNames); emit finished(m_FilesList); emit finished(this); this->quit(); exec(); qDebug()<<"end"<<this; } void emitStop() { emit finished(this); }
пробовал без exec() - рекурсия поиска файлов прерывается вроде
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: daimon от Марта 11, 2012, 02:38
оффтоп: Подскажите как Qt библиотеки в среду MSVS 2010 встроить?
первый делом советую скомпилить qt статикой и без рантайма, а потом уже встраивать в студию рантайм зло - переносимости никакой, бывали случали .net framework криво встал и в приложение просто нельзя было ввести текст, хотя оно работало и я не говорю ещё про ошибки запуска, если нет нужных либ рантайма http://www.prog.org.ru/topic_20045_0.html минусы статики - долго линкуется и qt весит в 3 раза больше на диске (без компиляции примеров) плюсы - переносимость, один исполняемый файл
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: LisandreL от Марта 11, 2012, 06:39
connect(threadFileFind,SIGNAL(finished(CFileFindThread*)),this,SLOT(deleteThread(CFileFindThread*))); У потока есть свой finished() без параметров. Есть слот deleteLater - зачем своё писать. пробовал без exec() - рекурсия поиска файлов прерывается вроде Явный вызов функции? Не срабатывает без exec? Вам показалось. :)
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: daimon от Марта 11, 2012, 14:36
connect(threadFileFind,SIGNAL(finished(CFileFindThread*)),this,SLOT(deleteThread(CFileFindThread*))); У потока есть свой finished() без параметров. Есть слот deleteLater - зачем своё писать. написал свой слот deleteThread(...) только для того, чтобы принудительно остановить и удалить работающий поток забыл добавить в пост важный код )) emitStop в CFileFindThread и коннект в CFileBrowser на вызов этого слота -при клике на кнопку, для генерации останова и удаления текущего потока C++ (Qt) void CFileBrowser::startFind() { if(!m_isRunningFileFindThread) { ui.listWidget->clear(); CFileFindThread * threadFileFind = new CFileFindThread(m_Path, m_FilterNames, this); connect(threadFileFind,SIGNAL(finished(CFileFindThread*)),this,SLOT(deleteThread(CFileFindThread*)));///сработает сразу после отработки потока и в случае, когда я сам сгенерирую этот сигнал с помощью кнопки (см ниже) connect(threadFileFind, SIGNAL(finished(QStringList)), this, SLOT(setFilesList(QStringList))); connect(threadFileFind,SIGNAL(currentProgress(int)),this,SLOT(setProgress(int))); connect(ui.pushButtonCancel, SIGNAL(clicked()),threadFileFind ,SLOT(emitStop())); ////////генерация останова для потока if(!m_isRunningFileFindThread) connect(ui.pushButtonStart, SIGNAL(clicked()), this, SLOT(startFind())); threadFileFind->start(); m_isRunningFileFindThread = true; } } void CFileBrowser::deleteThread( CFileFindThread* val )/////только потому, что поток локальный есть сигнально-слотовая связка, где есть указатель на текущий поток { if( val != NULL) { val->terminate(); val->deleteLater(); m_isRunningFileFindThread = false; } } void CFileBrowser::emitCancel()//знаю, что очень тупо (не знаю как изменить), так останавливаю поток через функцию класса родителя потока, генерирую клик на кнопку, в свою очередь кнопка вызывает метод у потока (emitStop()), который гененирует мой сигнал finished(CFileFindThread*), а из-за него уже вызывается функция deleteThread(...) и поток останавливается и удаляется { if(m_isRunningFileFindThread) { qDebug()<<"auto click cancel"; ui.pushButtonCancel->click(); } } void CFileBrowser::setFilesList( QStringList val ) { m_FilesList = val; bool select = true; for(int i=0; i<val.count();i++) { QListWidgetItem * tempItem = new QListWidgetItem(val[i], ui.listWidget); tempItem->setCheckState(Qt::CheckState(2*select)); } m_isRunningFileFindThread = false; emit finished(); } //////////// void CFileFindThread::run() { qDebug()<<"start"<<this; QDir dir(m_Path); m_FilesList = getListFilesFind(m_Path,m_FilterNames); emit finished(m_FilesList); emit finished(this); this->quit(); exec(); qDebug()<<"end"<<this; } void emitStop()////вот почему есть свой сигнал finished(), для того, чтобы знать указатель на текущий поток извне { emit finished(this); }
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: daimon от Марта 11, 2012, 14:54
пробовал без exec() - рекурсия поиска файлов прерывается вроде Явный вызов функции? Не срабатывает без exec? Вам показалось. :) Вы правы убрал и работает
Название: Re: QThread остановка потока с нормальным кодом возрата и без ошибки в QMutex
Отправлено: daimon от Марта 11, 2012, 14:59
Я пишу виджет, который ищет файлы по пути и с фильтром поиска, файлы пока добавляются в листвиджет с чекбоксами, по чекбоксам определяю какие файлы отослать на обработку дальше
можно ли как-то упростить задачу?
например, есть проект отображения директории с чекбоксами на папках и файлах, там не нравиться как в итоге на модель данных влияют чекбоксы, прошу проверить)) спс
с точки зрения отображения данных на окне думаю как-то изменить (листвиджет с большим количеством данных тормозит при смене состояния элемента), рекурсивный потоковый поиск оставлю
http://qt-project.org/forums/viewthread/5051/P30 (http://qt-project.org/forums/viewthread/5051/P30) https://gitorious.org/checkableproxymodel#more (https://gitorious.org/checkableproxymodel#more)
|