Название: Создание потока и креш программы
Отправлено: Max Payne от Декабрь 02, 2010, 05:41
Программа передает файлы по tcp, есть список файлов, пользователь кликает, создается обьект клиента и выполняется передача и запись данных в новый файл . Задача засунуть каждый обьект класа клиента в отдельный поток. Тоесть на каждый клик пользователя файл передается в отдельном потоке. Задача вроде тривиальна, но не могу понять что я не так сделал. Я создал класс наследованый от QThread и в нем создаю обьект класса клиента: class Thread_of_pdf : public QThread { Q_OBJECT public: Thread_of_pdf (QStringList List_param, QObject *parent); void run();
signals: void write_file_fin (); void down_label (QString n); void set_value_prog (int b); void start_trans(); void close_pro (); void abort_con();
private : QStringList param_of_connection;
}; вот реализация Thread_of_pdf::Thread_of_pdf (QStringList List_param, QObject *parent) { param_of_connection = List_param; }
void Thread_of_pdf::run() { QString address = param_of_connection.at(0); QString Port = param_of_connection.at(1); QString word = param_of_connection.at(2);
Client_pdf *qw = new Client_pdf(address ,Port,word ) ; // вот тут креш, даже не создает обьект connect (qw, SIGNAL(destroyed()), qw, SLOT(deleteLater())); connect(qw, SIGNAL(set_value_prog(int)),this, SIGNAL(set_value_prog(int))); connect (qw, SIGNAL(close_pro()), this , SIGNAL(close_pro())); connect (qw, SIGNAL(start()), this, SIGNAL(start_trans())); connect (qw, SIGNAL(write_file_fin()), this, SIGNAL(write_file_fin())); connect (qw, SIGNAL(down_label(QString)),this, SIGNAL(down_label(QString))); connect (this, SIGNAL(abort_con()),qw, SLOT(abort_send()));
} где клиент class Client_pdf : public QDialog { Q_OBJECT
public: Client_pdf(QString &str_port , QString &str_adress , QString &key_ret ); struct pol { QString adr ; QString port_p ; QString key_pv ; }; struct tab { QStringList ex_word; QStringList ex_path; }; private:
QTcpSocket *tcpSock_pdf; quint16 blockSize; int socketDescriptor; QString fer, str_port, str_adress; QString key_ber ; pol NS ; //QString receive_text; QByteArray ter; //bool ind_send_mes; //QTimer *ret; quint64 rtg; qint64 nextBlockSize; bool qw; qint64 y; //QString file_type; private slots: //void request(); void read (); void displayError(QAbstractSocket::SocketError socketError); void send_rec_v(); void abort_send();
signals : void write_file_fin (); //void up_label (QString m); void down_label (QString n); void set_value_prog (int b); void start(); void max_value(int); void close_pro ();
}; и его реализация Client_pdf::Client_pdf(QString &str_adress,QString &str_port, QString &key_ret) // : QDialog(parent) { qw = false; rtg = 0; NS.adr = str_adress ; NS.port_p = str_port; NS.key_pv = key_ret ; qDebug ()<< NS.adr <<" " << NS.port_p << " " << NS.key_pv ;
// find out which IP to connect to key_ber = key_ret ;
QString ipAddress; QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); // use the first non-localhost IPv4 address for (int i = 0; i < ipAddressesList.size(); ++i) { if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) ipAddress = ipAddressesList.at(i).toString(); } // if we did not find one, use IPv4 localhost if (ipAddress.isEmpty()) ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
//ter.append("FW"); tcpSock_pdf = new QTcpSocket(this);
connect (tcpSock_pdf ,SIGNAL(connected()) , this , SLOT(send_rec_v())); connect (tcpSock_pdf, SIGNAL(readyRead()),this, SLOT(read())); connect(tcpSock_pdf, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError))); connect (tcpSock_pdf,SIGNAL(disconnected()),tcpSock_pdf,SLOT(deleteLater())); //connect(ret, SIGNAL(timeout()),this, SLOT(send_sig_em()));
blockSize = 0; tcpSock_pdf->abort(); tcpSock_pdf->connectToHost(NS.adr, NS.port_p.toInt()); } void Client_pdf::read() { int prog_val; QString bc; bc = QDir::currentPath(); bc.append("/more_m/"); QStringList ert = NS.key_pv.split("/"); bc.append(ert.last()); QString lab_down = NS.key_pv; QFile file (bc);
QDataStream in(tcpSock_pdf); in.setVersion(QDataStream::Qt_4_0);
if (qw == false) { emit down_label(lab_down); emit start(); in >> y; // emit max_value (y); qDebug() << " YYYY " << y; qw= true; }
if (blockSize == 0) {
if (tcpSock_pdf->bytesAvailable() < (int)sizeof(quint16)) return; } while (file.size()<y) { tcpSock_pdf->waitForReadyRead(); int ret; if (tcpSock_pdf->bytesAvailable()) {
//QFile file(bc); if (file.open(QIODevice::Append)) { QByteArray buf = tcpSock_pdf->readAll();//читаем все данные из сокета if (buf.size()) {//если данные считаны //qDebug() << "Buff SIZE" << buf.size() << "FILE SIZE " << file.size(); file.write(buf);//записываем байты
} qDebug() << "tcpSock_pdf->bytesAvailable() " << tcpSock_pdf->bytesAvailable() << " FILE SIZE " << file.size();
file.close(); tcpSock_pdf->flush(); ret = ((int)file.size()/(y/100)); qDebug() << y<<" Progress value " << ret; } } if (prog_val!=ret) { emit this->set_value_prog(ret); prog_val = ret; } } tcpSock_pdf->disconnectFromHost(); }
void Client_pdf::displayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: { // emit write_file_fin (); break; } case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("DemAsTPro"), tr("The host was not found. Please check the " "host name and port settings.")); break; case QAbstractSocket::ConnectionRefusedError: QMessageBox::information(this, tr("DemAsTPro"), tr("The connection was refused by the peer. " "Make sure the fortune server is running, " "and check that the host name and port " "settings are correct.")); break; default: QMessageBox::information(this, tr("DemAsTPro"), tr("The following error occurred: %1.") .arg(tcpSock_pdf->errorString())); }
} void Client_pdf::send_rec_v() { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_0); out << (quint16)0; out << NS.key_pv; out.device()->seek(0); out << (quint16)(block.size() - sizeof(quint16)); tcpSock_pdf->write(block); tcpSock_pdf->flush(); tcpSock_pdf->waitForReadyRead() ;
} Подскажите где ошибка...
Название: Re: Создание потока и креш программы
Отправлено: asvil от Декабрь 02, 2010, 11:00
Посмотрите stderr, может там есть некоторый вывод. Возможно QtGui классы нельзя создавать в потоке. Вообще если вы в потоке хотите работать с событиями и сигналослотами необходимо вызывать цикл обработки сообщений потока, те QThread::exec() в методе run. mythread::run() { //init(); bool ok = exec(); // ВНИМАНИЕ когда вызывается QThread::quit() из другого потока у меня почему-то сюда выполнение не доходит. }
И еще, я там мельком заметил у Вас сокеты. У меня возникала проблема с тем, что поток ни в какую не хотел умирать, те quit() выполнялся, а последующий wait() ждал бесконечно долго. Это могло происходить из-за того, что сокет создаваясь инсталлировал qsocketnotifier в event loop потока и видимо делал это некорректно. Конечно может быть я как не так использовал потоки\сокеты.
Название: Re: Создание потока и креш программы
Отправлено: Max Payne от Декабрь 02, 2010, 19:32
Я уже перепробовал все, креш прям на создании обьекта Client_pdf *qw = new Client_pdf(address ,Port,word ) ; Не могу ни ерор отследить ничего просто вылетает и все , окошко ошибки виндовс Microsoft Visual C++ Runtime Library "This application has requested the Runtime to terminate it in an unusual way. "
Название: Re: Создание потока и креш программы
Отправлено: asvil от Декабрь 02, 2010, 19:37
А почему Вы решили конструктор родителя QDialog не вызывать?
Название: Re: Создание потока и креш программы
Отправлено: sadhu от Декабрь 02, 2010, 21:52
я наверно не сильно соригинальничаю, если скажу что Qt не позволяет создавать обьекты класса QWidget и его потомков не в основном потоке. Думал общеизвестный факт :) Как решение предложил бы сделать класс фабрику виджетов и подключать его ко всем потокам, создаваемым при выполнении программы.
Название: Re: Создание потока и креш программы
Отправлено: Max Payne от Декабрь 03, 2010, 18:11
Точно, все исправил, у наследовал от сокета класс и все.. Но есть все таки ошибка, не могу найти , пишет что я пытаюсь создать виджет в моем потоке... Вот код привожу: функция отвечающая за прерывание передачи файла: void Client_pdf::abort_send() { QTcpSocket *tcpSock_p = new QTcpSocket(); if (!tcpSock_p->setSocketDescriptor(socketDescriptor)) { emit error(tcpSock_p->error()); return; } tcpSock_p->disconnectFromHost();
QFile vc(NS.key_pv); if (vc.exists()) { if(vc.remove()== true) { emit this->error_download_file(); //сигнал ловится в основном потоке и пишется ошибка "передача прервана" return; } } emit close_pro(); tcpSock_p->deleteLater(); } // дальше после выхода с слота просто вылетает // в QApplication Output выводит ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", //filekernel\qwidget.cpp, line 1133
Вызывается сигналом с другого класса , который состоит из прогресс бара и кнопки, обрабатывается в основном потоке... Не могу догнать к чему, у меня в цикле обработки потока нету ни одного виджета и ни одного наследника..
Название: Re: Создание потока и креш программы
Отправлено: Max Payne от Декабрь 05, 2010, 22:22
Всем спасибо , пока что понял и решил все, разобрался... Спасибо всем за помощь... 8) 8) 8)
|