Russian Qt Forum
Ноябрь 23, 2024, 08:37 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QThread остановка потока без ошибки в QMutex или свой поисковик файлов  (Прочитано 7521 раз)
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;
}
 

при таком использовании потока происходит ошибка


 
« Последнее редактирование: Март 11, 2012, 15:00 от daimon » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #1 : Март 10, 2012, 18:54 »

1) exec() в вашем коде не нужен
2) terminate() опасен и может приводить к разнообразным ошибкам.
Для прерывания используйте флаг который будете проверять периодически в getListFilesFind. + wait
Записан
lolbla2
Гость
« Ответ #2 : Март 10, 2012, 19:14 »

оффтоп:
Подскажите как Qt библиотеки в среду MSVS 2010 встроить?
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #3 : Март 10, 2012, 19:22 »

lolbla2, http://qt.nokia.com/downloads/visual-studio-add-in
Записан
daimon
Гость
« Ответ #4 : Март 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() - рекурсия поиска файлов прерывается вроде
« Последнее редактирование: Март 11, 2012, 14:34 от daimon » Записан
daimon
Гость
« Ответ #5 : Март 11, 2012, 02:38 »

оффтоп:
Подскажите как Qt библиотеки в среду MSVS 2010 встроить?

первый делом советую скомпилить qt статикой и без рантайма, а потом уже встраивать в студию

рантайм зло - переносимости никакой, бывали случали .net framework криво встал и в приложение просто нельзя было ввести текст, хотя оно работало и я не говорю ещё про ошибки запуска, если нет нужных либ рантайма

http://www.prog.org.ru/topic_20045_0.html

минусы статики - долго линкуется и qt весит в 3 раза больше на диске (без компиляции примеров)
плюсы - переносимость, один исполняемый файл
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #6 : Март 11, 2012, 06:39 »

Цитировать
connect(threadFileFind,SIGNAL(finished(CFileFindThread*)),this,SLOT(deleteThread(CFileFindThread*)));
У потока есть свой finished() без параметров. Есть слот deleteLater - зачем своё писать.

Цитировать
пробовал без exec() - рекурсия поиска файлов прерывается вроде
Явный вызов функции? Не срабатывает без exec? Вам показалось. Улыбающийся
Записан
daimon
Гость
« Ответ #7 : Март 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);
}
 
« Последнее редактирование: Март 11, 2012, 14:49 от daimon » Записан
daimon
Гость
« Ответ #8 : Март 11, 2012, 14:54 »

Цитировать
Цитировать
пробовал без exec() - рекурсия поиска файлов прерывается вроде
Явный вызов функции? Не срабатывает без exec? Вам показалось. Улыбающийся
Вы правы убрал и работает
Записан
daimon
Гость
« Ответ #9 : Март 11, 2012, 14:59 »

Я пишу виджет, который ищет файлы по пути и с фильтром поиска, файлы пока добавляются в листвиджет с чекбоксами, по чекбоксам определяю какие файлы отослать на обработку дальше

можно ли как-то упростить задачу?

например, есть проект отображения директории с чекбоксами на папках и файлах, там не нравиться как в итоге на модель данных влияют чекбоксы, прошу проверить)) спс

с точки зрения отображения данных на окне думаю как-то изменить (листвиджет с большим количеством данных тормозит при смене состояния элемента), рекурсивный потоковый поиск оставлю


http://qt-project.org/forums/viewthread/5051/P30
https://gitorious.org/checkableproxymodel#more
« Последнее редактирование: Март 11, 2012, 15:57 от daimon » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.179 секунд. Запросов: 23.