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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [Qt 4.4] Поток и зависание  (Прочитано 15011 раз)
Urvin
Гость
« : Ноябрь 27, 2008, 17:38 »

Я хотел, чтобы у меня в программе по нажатию кнопки "старт" запускался хитрый процесс, который в зависимости от удачливости пользователя мог бы идти различное время.
И точно также я хотел, чтобы затянувшийся процесс пользователь мог остановить, нажав на кнопку "стоп"

Все работает отлично, окромя остановки потока - GUI замораживается и не дает на жать на кнопку остановки.

Подскажите, пожалуйста, как это исправить!

в функции run моего потока - только расчеты и вызов сиигналов (без различных таймеров и exec).
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Ноябрь 27, 2008, 18:02 »

Код в студию.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Urvin
Гость
« Ответ #2 : Ноябрь 27, 2008, 18:11 »

markovthread.h
Код:
#ifndef MARKOVTHREAD_H
#define MARKOVTHREAD_H

#include <QThread>
#include <QString>
#include <QStringList>

class markovThread : public QThread {
    Q_OBJECT

    public:
        QString codeText;
        QString inputStr;

        markovThread();
        void run();

    signals:
        void messageGot(QString);
        void resultGot(QString);

    private:
        int checkSyntax(QString line);
        int interp(QString line, QString &str);
};


#endif // MARKOVTHREAD_H

markovthread.cpp
Код:
#include "markovthread.h"

markovThread::markovThread()
{
    codeText = "";
}

void markovThread::run()
{
    if (codeText=="") {
        emit messageGot("No code found");
        return;
    }
    if (inputStr=="") {
        emit messageGot("No input string specified");
        return;
    }

    codeText.replace("\r","");
    QStringList commands = codeText.split("\n", QString::SkipEmptyParts);

    int i, j;

    // Проверка синтаксиса каждой из строк
    bool allright=true;
    for (int i=0; i<commands.size(); i++)
    {
        j=checkSyntax(commands.at(i));

        if (j==2) {
            emit messageGot("Line " + QString("%1").arg(i+1) + ": No replace operator");
            allright=false;
        }
        else if (j==3)
        {
            emit messageGot("Line " + QString("%1").arg(i+1) + ": Two or more replace operators");
            allright=false;
        }
    }
    // Если имеются ошибки, дальшейшее исполнение невозможно
    if (!allright) {
        return;
    }


    // Непосредственное выполнение программы
    j=0; i=0;
    while (true)
    {
        j=interp(commands.at(i),inputStr);

        if (   j==0) {
            if (i<commands.size()-1)
            {
                i++;
            }
            else
            {
                emit messageGot("End with no finishing operator");
                break;
            }
        }
        else if(j==1)
        {
            emit resultGot(inputStr);
            i=0;
        }
        else if(j=2)
        {
            emit messageGot("End with finishing operator");
            break;
        }
    }
}



int markovThread::checkSyntax(QString line)
{
    // Если строка пустая, то ее синтаксис верено
    if (line=="")
    {
        return 1;
    }

    // Если строка начинается с обозначения комментария, ее синтаксис верен
    if (line.left(2)=="//")
    {
        return 1;
    }

    //Проверка расположения оператора замены
    // Если оператор в строке не найден - ошибка
    if (line.indexOf("->")==-1)
    {
        return 2;
    }
    // Если в строке более одного оператора замены, строка не верна
    if (line.lastIndexOf("->") != line.indexOf("->"))
    {
        return 3;
    }

    // Дальнейших проверок не требуется, строка синтаксически верна
    return 0;
}

// Функция интерпретирования языка.
// 0 - следующая строка
// 1 - программа заново
// 2 - остановка программы
int markovThread::interp(QString line, QString &str)
{
    // Находим пустую строку или комментарий, переходим на следующую строку
    if (line=="") {
        return 0;
    }
    if (line.left(2)=="//") {
        return 0;
    }


    QString s1,s2;
    int p=-1;

    // Поиск завершающего оператора
    p = line.indexOf("->.");
    if (p>-1)
    {
        s1=line.mid(0,p);
        s2=line.mid(p+3);

        // Первый операнд пустой/не пустой
        if (s1=="") {
            str = s2+str;
            return 2;
        }
        else {
            p = str.indexOf(s1);
            if (p>-1) {
                str.replace(s1,s2);
                return 2;
            }
            else {
                return 0;
            }
        }
    }

    // Поиск исполняемого оператора
    p = line.indexOf("->");
    if (p>-1)
    {
        s1=line.mid(0,p);
        s2=line.mid(p+2);

        if (s1=="")
        {
            str=s2+str;
            return 1;
        }
        else
        {
            p=str.indexOf(s1);
            if (p>-1)
            {
                str.replace(s1,s2);
                return 1;
            }
            else
            {
                return 0;
            }
        }
    }

    return 0;
}


Запуск и остановка:
Код:
void MainWindow::btnStart_Clicked()
{
    edtExec->setText("");
    lstMessages->clear();

    btnStart->setEnabled(false);
    btnStop->setEnabled(true);

    mThread->codeText="a->b";
    mThread->inputStr="aaabbb";
    mThread->start();
}

void MainWindow::btnStop_Clicked()
{
    mThread->quit();
}

если в старт поставить
mThread->codeText="b->b";
цикл станет бесконечным - это нормально, но надо иметь возможность остановить
Записан
SASA
Гость
« Ответ #3 : Ноябрь 27, 2008, 18:26 »

Цитировать
void QThread::quit ()   [slot]

Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0).

This function does nothing if the thread does not have an event loop.

Я бы написал
Код:
 mThread->terminate();
P.S. Настараживает 
Код:
else if(j=2)
Записан
Urvin
Гость
« Ответ #4 : Ноябрь 27, 2008, 18:32 »

SASA, спасибо, исправил. Тем не менее - остается такая проблема, что при запуске бесконечного цикла GUI зависает и не отвечает на мои попытки нажать на кнопку остановки
Записан
ритт
Гость
« Ответ #5 : Ноябрь 27, 2008, 18:46 »

пиши exec
без ивентлупа в данном случае ты только косяки заработаешь...
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #6 : Ноябрь 27, 2008, 18:55 »

terminate() я бы не рекомендовал бы использовать. Это не правильное решение. Предлагаю следующее:

Код
C++ (Qt)
void markovThread::exitThread()
{
   if (!isRunning())
       return;
 
   m_stopMutex.lock();
   m_stopped = true;
   m_stopMutex.unlock();
 
   wait();
}
 
void markovThread::run()
{
   m_stopMutex.lock();
   m_stopped = false;
   m_stopMutex.unlock();
 
   ...
 
   while (!stopped)
   {
        ....
   }
}
 
void MainWindow::btnStop_Clicked()
{
   mThread->exitThread();
}

Вам нужно будет добавить 2 члена класса:

bool m_stopped;
QMutex m_stopMutex;
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #7 : Ноябрь 27, 2008, 19:01 »

Тем не менее - остается такая проблема, что при запуске бесконечного цикла GUI зависает и не отвечает на мои попытки нажать на кнопку остановки

Где-то ошибка в логике работы программы. Нужно предусмотреть все случаи, чтобы небыло бесконечныйх циклов
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Urvin
Гость
« Ответ #8 : Ноябрь 27, 2008, 19:13 »

Случай бесконечного цикла, как ни странно обязан быть, и поэтому я выношу его в отдельный поток.
Но цикл надо останавливать.. Хотелось бы именно поточно, не изобретая прочих велосипедов
Записан
SASA
Гость
« Ответ #9 : Ноябрь 29, 2008, 10:07 »

Про terminate() согласен с pastor.
Про вечный цикл. Можно в конце поставить msleep(1). Может поможет.
А как происходит connect c messageGot(QString) и resultGot(QString). Установлен ли там Qt::ConnectionType.

Где-то ошибка в логике работы программы. Нужно предусмотреть все случаи, чтобы небыло бесконечныйх циклов
У меня все потоки с вечными циклами - работают отлично.
Записан
Urvin
Гость
« Ответ #10 : Ноябрь 29, 2008, 12:30 »

SASA, это в конструкторе MianWindow:
Код:
mThread = new markovThread();
    connect(mThread, SIGNAL(messageGot(QString)),this, SLOT(mThread_messageGot(QString)));
    connect(mThread, SIGNAL(resultGot(QString)),this, SLOT(mThread_resultGot(QString)));
    connect(mThread, SIGNAL(finished()),this, SLOT(mThread_finished()));
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #11 : Ноябрь 29, 2008, 16:29 »

У меня все потоки с вечными циклами - работают отлично.

Я имел ввиду что нужно иметь условие выхода с такого цикла. Выше я привел такой код.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
SASA
Гость
« Ответ #12 : Декабрь 02, 2008, 17:02 »

SASA, это в конструкторе MianWindow:
Код:
mThread = new markovThread();
    connect(mThread, SIGNAL(messageGot(QString)),this, SLOT(mThread_messageGot(QString)));
    connect(mThread, SIGNAL(resultGot(QString)),this, SLOT(mThread_resultGot(QString)));
    connect(mThread, SIGNAL(finished()),this, SLOT(mThread_finished()));
Попробуй так
Код:
    connect(mThread, SIGNAL(messageGot(QString)),this, SLOT(mThread_messageGot(QString)), Qt::QueuedConnection);
    connect(mThread, SIGNAL(resultGot(QString)),this, SLOT(mThread_resultGot(QString)), Qt::QueuedConnection);
    connect(mThread, SIGNAL(finished()),this, SLOT(mThread_finished()), Qt::QueuedConnection);
Записан
Urvin
Гость
« Ответ #13 : Декабрь 02, 2008, 23:11 »

все равно интерфейс виснет Обеспокоенный
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #14 : Декабрь 03, 2008, 11:42 »

все равно интерфейс виснет Обеспокоенный

Отлавите тот момент, где нет полезных вычислений в бесконечном цикле и усыпите на определенное время поток. Должно помочь.

Код
C++ (Qt)
void markovThread::run()
{
   ...
 
   while (<>)
   {
        ....
        if (<>) {
            //do something
        } else if (<>) {
           // do something else
        } else {
           //do nothing
           msleep(10);
        }
 
   }
}

возможный код завершения цикла я привел выше.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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