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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: как правильно работать с QThread? (закачка файла в треде)  (Прочитано 7051 раз)
Unnamed_Hero
Гость
« : Июль 09, 2008, 09:49 »

Хочу понять, как правильно работать с тредами. Почитав книги по qt4, понял мало, там очень сухо всё описано.

Хочу сделать тред, в котором будет проходить закачка файла.
Соответственно, при создании в него должны передаваться параметры  - откуда и куда качать файл.

Значит в треде должны быть свои сигналы и слоты.

В методе треда run() последней строчкой стоит exec()

Если стартовать тред с помощью start(), то он запускается и сразу же помирает, не скачав и байта (тред не ловит ни слотов, ни сигналов). Если запускать с помощью run(), то тред отрабатывает, но после отработки тред виснет, т.е. программа висит в ожидании. Если в программе  нажать на quit, то, видимо, тред грохается и программа продолжает работать. повторное нажатие на quit срабатывает нормально.

Вероятно, я не могу выйти из EventLoop, вызов quit(), exit(0), exit() - не помогают.

Ну, и главный номер программы -  мой ugly code:
тредовый .h
Код:
class get_xml : public QThread
{
Q_OBJECT
public:

get_xml (QObject *parent = 0,QStringList *_initList=0);
~get_xml ();


void run ();
private:
QHttp http;

QFile xmlfile;

QByteArray result;
QStringList* initList;

QString charfile;
private slots:
void readData();
void save2File();

signals:
void finita();

};

тредовый .cpp

Код:
get_xml::get_xml (QObject *parent,QStringList *_initList)
:initList (_initList)
{

}
void get_xml::run ()
{

qDebug ("getXML STARTED");

QHttpRequestHeader header ("GET", initList->at(1),1,1);

QByteArray opts;

connect (&http,SIGNAL (readyRead (QHttpResponseHeader)),this, SLOT (readData()));
connect (&http,SIGNAL (done (bool)),this,SLOT (save2File()));
header.setContentType("application/x-www-form-urlencoded");
header.setValue("Host", "bla-bla.com");
http.setHost ("bla-bla.com");
xmlfile.setFileName (initList->at(0)+initList->at(4)+QDir::separator()+file.fileName());
opts.append ("<ny cool opts>");
http.request (header,opts,0);
exec();


}

get_xml::~get_xml()
{

qDebug ("xml thread убилсо");

}

void get_xml::readData()
{

qDebug ("тяну-потяну XML...");
result.append (http.readAll());

void get_xml::save2File ()
{
disconnect (&http,0,0,0);
xmlfile.open (QIODevice::WriteOnly);
qDebug ()<<"downloading complete"
xmlfile.write (result);
xmlfile.close();

emit (finita());
}


В главном классе
в .h
Код:
get_xml *myCurrSkill;

в .cpp

Код:
myCurrSkill = new get_xml (this,&initList);
bool skillConn (false);
connect (myCurrSkill,SIGNAL (finita()),this,SLOT (charCSkillReady()));
//myCurrSkill->start();
myCurrSkill->run();

....................
.....................
void char_Sheet::charCSkillReady ()
{

disconnect (myCurrSkill,0,0,0);
myCurrSkill->quit();
myCurrSkill->deleteLater();
}

Записан
SASA
Гость
« Ответ #1 : Июль 09, 2008, 10:17 »

Первое что бросается в глаза: для запуска надо вызывать QThread::start(). Если мы вызываем run(), никаких потоков не создаётся. Просто функция исполняется в вызывающем потоке.
О потоках неплохо написано у Бланшет. Живую ссылку на книгу можно поискать здесь:
http://prog.org.ru/forum/index.php/topic,765.0.html
« Последнее редактирование: Июль 09, 2008, 10:23 от SASA » Записан
Unnamed_Hero
Гость
« Ответ #2 : Июль 09, 2008, 10:33 »

А если вызывать через start(), как я уже и писал - то не создаётся EventLoop треда, т.е. слоты и сигналы просто не обрабатываются, следовательно файл не скачивается...
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #3 : Июль 09, 2008, 14:45 »

А если вызывать через start(), как я уже и писал - то не создаётся EventLoop треда, т.е. слоты и сигналы просто не обрабатываются, следовательно файл не скачивается...

Вы противоречите ассистанту и опыту людей. При возове start() вызываеться метод run() и так было и есть сейчас.

Цитировать
void QThread::run ()   [virtual protected]
The starting point for the thread. After calling start(), the newly created thread calls this function. The default implementation simply calls exec().
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Alex03
Гость
« Ответ #4 : Июль 10, 2008, 07:52 »

Unnamed_Hero у Вас проблема в следующем:
QHttp http - член класса потомка от QThread, который создаётся в главном потоке приложения, соответственно http "принадлежит" главному потоку. Далее Вы его сигналы коннектите к этому потомку от QThread, который тоже в главном потоке.
Соответственно вызову exec() который в run просто нечего обрабатывать, у порождённого потока нет соответствующих объектов.
Т.е. если Вы перенесёте QHttp http например, на стек в run() то всё начнёт работать...
НО! простой connect() между http и слотами потомка QThread будет "межпоточный", и следовательно сама обработка будет в главном потоке, что не соответствует задуманной логике. Поэтому такие connect-ы надо делать с Qt::DirectConnection.

P.S. Иногда можно не мудрить с потоками а всё делать в главном потоке, для работы с сокетами и т.д. в Qt для этого всё есть. Иначе надо хорошо представлять как всё это работает, использовать механизмы межпоточной синхронизации и т.д., ибо в противном случае трудноотлавливаемые грабельки будут вылазить очень долго.
Записан
Unnamed_Hero
Гость
« Ответ #5 : Июль 10, 2008, 09:53 »

спасибо за разъяснение.

В итоге сделал такую реализацию, которая даже работает:

в *.h треда заменил QHttp http на QHttp *_http;

В стеке run() объявил QHttp http, сделал  _http = &http;

и вне run () общался c http через _http->

В главном классе myCurrSkill->start();myCurrSkill->wait();
Записан
Alex03
Гость
« Ответ #6 : Июль 10, 2008, 12:54 »

в *.h треда заменил QHttp http на QHttp *_http;
В стеке run() объявил QHttp http, сделал  _http = &http;
Можно было и new....
В главном классе myCurrSkill->start();myCurrSkill->wait();
Если wait() то какой смысл в отдельном потоке?

Про коннекты то поняли?
readyRead() и done() надо коннектить с Qt::DirectConnection
а finita() с Qt::QueuedConnection

Записан
Unnamed_Hero
Гость
« Ответ #7 : Июль 10, 2008, 15:02 »

wait() это пока что для отладки и тестов. и для экспериментов.

Про коннекты тоже понятно, спасибо. Так и было сделано, просто в предыдущем сообщении этого я не указал.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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