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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание потока и креш программы  (Прочитано 4941 раз)
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() ;

}


Подскажите где ошибка...

Записан
asvil
Гость
« Ответ #1 : Декабрь 02, 2010, 11:00 »

Посмотрите stderr, может там есть некоторый вывод. Возможно QtGui классы нельзя создавать в потоке.
Вообще если вы в потоке хотите работать с событиями и сигналослотами необходимо вызывать цикл обработки сообщений потока, те QThread::exec() в методе run.
Код:
mythread::run()
{
//init();
bool ok = exec();
// ВНИМАНИЕ когда вызывается QThread::quit() из другого потока у меня почему-то сюда выполнение не доходит.
}
И еще, я там мельком заметил у Вас сокеты. У меня возникала проблема с тем, что поток ни в какую не хотел умирать, те quit() выполнялся, а последующий wait() ждал бесконечно долго.
Это могло происходить из-за того, что сокет создаваясь инсталлировал qsocketnotifier в event loop потока и видимо делал это некорректно. Конечно может быть я как не так использовал потоки\сокеты.
Записан
Max Payne
Гость
« Ответ #2 : Декабрь 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.
 "
Записан
asvil
Гость
« Ответ #3 : Декабрь 02, 2010, 19:37 »

А почему Вы решили конструктор родителя QDialog не вызывать?
Записан
sadhu
Гость
« Ответ #4 : Декабрь 02, 2010, 21:52 »

я наверно не сильно соригинальничаю, если скажу что Qt не позволяет создавать обьекты класса QWidget и его потомков не в основном потоке.
Думал общеизвестный факт Улыбающийся
Как решение предложил бы сделать класс фабрику виджетов и подключать его ко всем потокам, создаваемым при выполнении программы.
Записан
Max Payne
Гость
« Ответ #5 : Декабрь 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

Вызывается сигналом с другого класса , который состоит из прогресс бара и кнопки, обрабатывается в основном потоке...
Не могу догнать к чему, у меня в цикле обработки потока нету ни одного виджета и ни одного наследника..
Записан
Max Payne
Гость
« Ответ #6 : Декабрь 05, 2010, 22:22 »

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


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