Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Взаимодействие с главным потоком 
V
    Опции темы
RobRoj7779
Дата 29.8.2009, 22:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Здравствуйте, помогите новичку разобраться с главным потоком.
Просмотрел предыдущие темы по подобным вопросам, но к сожалению не понял. Помогите.
пытаюсь писать на QT4. В диалоговой форме код отработал нормально, но мне его нужно перенести на главную форму приложения.
Суть проблемы: во вторичном потоке создаю строку. Ее нужно отобразить на главной форме. В главном потоке динамически.
При переносе кода от QDialog. Строка отображается только при старте потока, и чтобы увидеть новую строку, снова стартую поток. Необходимо увидеть динамику, как в Таймере. Таймер для задачи не подошел, поэтому пытаюсь понять работу потоков.
При использовании Mutex, PostEvent программа висит

*.h
class MyPotok : public QThread
{
    Q_OBJECT
signals:
    void currentValueV(QString);
    void currentValueA(QString);

public:
    MyPotok();
    void stop();
    QString StrA, StrVal, StrPak;

protected:
    void run();
private:
    volatile bool stopped;
    QMutex mutex;
};

*.c
void MyPotok::run() 
{
----------
    try{
        mutex.lock();
        while(!stopped){
                          формирую строку    StrA ;
                 emit currentValueA(StrA);
            if(!myValue) {
                               формирую строку    StrVal ;
                emit currentValueV(StrVal);
            }
            usleep(120000);
        }
        stopped = false;
        mutex.unlock();
    }
    catch(...){
                  -----------------------------
    }
}

int main(int argc, char ** argv)
{
    QApplication app( argc, argv );
    MainWindowImpl win;
    MyPotok threadA;
    win.show(); 
    win.connect(&threadA, SIGNAL(currentValueA(QString)),
                     &win, SLOT(startThread()));
    win.connect(&threadA, SIGNAL(currentValueV(QString)),
                     &win, SLOT(startThread()));
    win.connect(&win, SIGNAL(getSendPak(bool)),
                     &threadA, SLOT(run()));
    app.connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ) );
    return app.exec();
}

void MainWindowImpl::startThread()
{
    QString Ln;
    threadA.start();
    Ln = threadA.StrA;
    if(!threadA.myValue)
         Ln = threadA.StrVal;
}

void MainWindowImpl::stopThread()
{
    QString Ln;
    threadA.stop();
}

void MainWindowImpl::getSendPak()
{
    threadA.StrPak = EdSendPak->text();
    emit setSendPak(threadA.myValue = false);
}

void MainWindowImpl::closeEvent(QCloseEvent *event)
{
    threadA.stop();
    threadA.wait();
    event->accept();
}

Заранее благодарен за помощь.
PM MAIL   Вверх
andrew_121
Дата 29.8.2009, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 11
Всего: 33



Два раза прочел, и не понял smile 
Опишите пожалуйста последовательно.
И код поместите в тэги ""


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
null56
Дата 29.8.2009, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Цитата(andrew_121 @ 29.8.2009,  22:59)
Два раза прочел, и не понял smile 
Опишите пожалуйста последовательно.
И код поместите в тэги ""

ваще жесть... я тоже не догнал ))))
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 00:02 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



В диалоговой форме 3 кнопки "Старт", "Стоп" и "Переслать" При "Старт" стартует поток и создается строка Ln += номер. номер++
Строка обновляется через 120 мс. и передается на форму Edit1. При "Переслать" подобным образом создается другая строка и также передается на форму, но другому Edit2. При "Стоп" поток останавливается и Edit очищается. Так я вижу на форме изменяющиеся строки по счетчику через 120 мс. Такое можно реализовать в Timer но для задачи нужен поток. Поэтому пытаюсь его освоить. Код работает при QDialog, когда я создал диалоговое приложение. Нужно подобное написать для главного приложения.
При переносе кода строки на главной форме обновляются только при постоянном нажатии кнопки "Старт". Если нажал "Старт" один раз Edit1 пустой. Нужно нажать "Старт" (run() потока) и видеть изменяющие строки, до нажатия "Стоп"(stop() потока). Что я не понял или делаю не так?????? Помогите пожалуйста.
Код

*.h
class MyPotok : public QThread
{
    Q_OBJECT
signals:
    void currentValueV(QString);
    void currentValueA(QString);

public:
    MyPotok();
    void stop();
    QString StrA, StrVal, StrPak;

protected:
    void run();
private:
    volatile bool stopped;
    QMutex mutex;
};

*.c
void MyPotok::run() 
{
----------
    try{
        mutex.lock();
        while(!stopped){
                          формирую строку    StrA ;
                 emit currentValueA(StrA);
            if(!myValue) {
                               формирую строку    StrVal ;
                emit currentValueV(StrVal);
            }
            usleep(120000);
        }
        stopped = false;
        mutex.unlock();
    }
    catch(...){
                  -----------------------------
    }
}

int main(int argc, char ** argv)
{
    QApplication app( argc, argv );
    MainWindowImpl win;
    MyPotok threadA;
    win.show(); 
    win.connect(&threadA, SIGNAL(currentValueA(QString)),
                     &win, SLOT(startThread()));
    win.connect(&threadA, SIGNAL(currentValueV(QString)),
                     &win, SLOT(startThread()));
    win.connect(&win, SIGNAL(getSendPak(bool)),
                     &threadA, SLOT(run()));
    app.connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ) );
    return app.exec();
}

void MainWindowImpl::startThread()
{
    QString Ln;
    threadA.start();
    Ln = threadA.StrA;
    if(!threadA.myValue)
         Ln = threadA.StrVal;
}

void MainWindowImpl::stopThread()
{
    QString Ln;
    threadA.stop();
}

void MainWindowImpl::getSendPak()
{
    threadA.StrPak = EdSendPak->text();
    emit setSendPak(threadA.myValue = false);
}

void MainWindowImpl::closeEvent(QCloseEvent *event)
{
    threadA.stop();
    threadA.wait();
    event->accept();
}

PM MAIL   Вверх
andrew_121
Дата 30.8.2009, 00:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 11
Всего: 33



RobRoj7779, Приблизительно, что-то понял, не уверен. Ты очень тяжело объясняешь.
Выложи весь проект на какой-нить файлообменник, а ссылку сюда. Так скорее придет понимание.

Добавлено через 1 минуту и 25 секунд
Цитата(RobRoj7779 @  30.8.2009,  00:02 Найти цитируемый пост)
        mutex.lock();

Этого делать не надо!

Добавлено через 3 минуты и 49 секунд
По моему начал понимать.
Тебе нужно чтоб при нажатии кнопок в диалоге, запускался некий поток, что-то выполнял. И, при этом, по ходу выполнения, что-то отображалось в главном окне? Так?


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
null56
Дата 30.8.2009, 05:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Ну что бросается в глаза...
1) Функция run: Мьютекс стоит не там и где обращение к мьютексу со стороы класса MainWindowImpl?
а) если поток работает постоянно, то как же мьютекс будет разблокироваться, если ты постоянно в цикле, а разблокируешь его только после выхода из цикла
б) если ты используешь мьютекс для синхронизации доступа к разделяемым ресурсам, то и на принимающей стороне должен его контроллировать доступ к твоим публичным переменным
Код

QString StrA, StrVal, StrPak;

Но я смотрю ты решился на такое
Код

    win.connect(&threadA, SIGNAL(currentValueA(QString)),
                     &win, SLOT(startThread()));
    win.connect(&threadA, SIGNAL(currentValueV(QString)),
                     &win, SLOT(startThread()));

то получается, что у тебя после генерации сигнала внутри работающего потока, поток стартует опять незавершаясь, и ты нарываешься на свой же заблокированный мьютекс...
И
почему бы тогда не передать значение прямиком в слот и за синхронизацию межпоточного взаимодействия будет отвечать уже механизм сигналов и слотов
Но вообще говоря, алгоритм ВООБЩЕ не понятен, чего ты хочешь таким образом добиться
ЗЫ: если тебе нужны миллисекунды, то есть аналог
Код

void QThread::msleep ( unsigned long msecs )   [static protected]
Causes the current thread to sleep for msecs milliseconds.

ЗЫ2: try->catch не нужен... на сколько мне известно Qt нигде не генерит исключения, всюду пользуются assert и ко...

2) Слота run нет у класса Qthread и в твоём наследнике + новый поток создавать можно только методом start, а в run реализация
Код

    win.connect(&win, SIGNAL(getSendPak(bool)),
                     &threadA, SLOT(run()));

есть start
Код

Public Slots
void quit ()
void start ( Priority priority = InheritPriority )
void terminate ()


Это сообщение отредактировал(а) null56 - 30.8.2009, 06:05
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Здравствуйте,

По моему начал понимать.
Тебе нужно чтоб при нажатии кнопок в диалоге, запускался некий поток, что-то выполнял. И, при этом, по ходу выполнения, что-то отображалось в главном окне? Так?

Да именно, так. Но как это сделать????????????

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

Как это сделать??????
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 09:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Код

win.connect(&threadA, SIGNAL(currentValueV(QString)),
                     &win, SLOT(startThread()));

void MainWindowImpl::startThread()
{
    QString Ln1, Ln1Hex;
    threadA.start();
    Ln1 = QString::fromLocal8Bit("Запущен поток");
    Ln1Hex = threadA.StrA;
    lbInfo_masA->setText(Ln1);
    lbInfo_masAHex->setText(Ln1Hex);
    if(!threadA.myValue){
        Ln1 = QString::fromLocal8Bit("Передано значение");
        Ln1Hex = threadA.StrVal;
        lbInfo_masB->setText(Ln1);
        lbInfo_masBHex->setText(Ln1Hex);
    }
}

Разве таким образом не передается строка в SLOT главной формы????????

PM MAIL   Вверх
andrew_121
Дата 30.8.2009, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 11
Всего: 33



Цитата(RobRoj7779 @  30.8.2009,  09:34 Найти цитируемый пост)
Разве таким образом не передается строка в SLOT главной формы????????

Нет.
Потому что сигнал передает строку, а слот не принимает аргументы.


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 10:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



т.е. мне нужно в startThread() написать startThread(QString str) и str передавать из алоговое currentValueV(QString). Так????????
Но почему эта тестовая программа работала, когда использовал диалоговое окно. Перенес код в приложение с главным окном и ни чего не увидел??????????????
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Это у меня тестовая прога, для понятия работы с потоком и взаимодействие с главным потоком приложения.
Файлообменниками не пользовался, может перекину на мыло. Уже парюсь 2-й день и понять не могу в что делаю не так. Помогите.
Когда был класс QDialog все работало. Теперь не вижу строк, которые должен был получать из потока, через 120 мс

Код

*h
signals:
    void currentValueV(QString);
    void currentValueA(QString);

*cpp

MyPotok::MyPotok(  ) 
{
    stopped = false;
}
//
void MyPotok::run() 
{
    int s1, s2;
    char buf[16];
    QString StrLog;
    unsigned char testBf[16];
    unsigned short lenBf;
    s1 = 0; s2 = 0;
    try{
        StrLog = QString::fromLocal8Bit(" Старт потока передачи ");
        SaveToFile(StrLog);
        while(!stopped){
            lenBf = ExecSendOpros(testBf); // заполняю testBf
            s1++;
                       // Создаю строку
            ::sprintf(buf, "%u", testBf[0]);
            StrA = QString::fromAscii(buf);
            for(int i=1; i<lenBf; i++){
                ::sprintf(buf, "%u", testBf[i]);
                StrA += " " + QString::fromAscii(buf);
            }
            StrA += " - ";
            StrA += QString::number(s1);
            StrA += " - ";
            StrA += QString::number(lenBf);
            StrLog = QString::fromLocal8Bit(" ->> Передан пакет = ");
            StrLog += StrA;
            SaveToFile(StrLog);
            emit currentValueA(StrA); // Нельзя ли так передать строку главному приложению (потоку)????????????
            if(!myValue) {
                s2++;
                lenBf = GetPak(StrPak, testBf, true);
                ::sprintf(buf, "%u", testBf[0]);
                StrVal = QString::fromAscii(buf);
                for(int i=1; i<lenBf; i++){
                    ::sprintf(buf, "%u", testBf[i]);
                    StrVal += " " + QString::fromAscii(buf);
                }
                StrVal += " - ";
                StrVal += QString::number(s2);
                StrVal += " - ";
                StrVal += QString::number(lenBf);
                StrLog = QString::fromLocal8Bit(" <<- Получен пакет = ");
                StrLog += StrVal;
                SaveToFile(StrLog);
                emit currentValueV(StrVal);
            }
            usleep(120000);
        }
        stopped = false;
    }
    catch(...){
        StrLog = QString::fromLocal8Bit(" Выход из цикла потока run() ");
        SaveToFile(StrLog); //Просто сохраняю в текстовый файл
    }
}
//
void MyPotok::stop() 
{
    QString StrLog;
    stopped = true;
    myValue = true;
    StrLog = QString::fromLocal8Bit(" Остановлен поток передачи ");
    SaveToFile(StrLog);
}

*cpp Главное окно приложения
кнопка "Старт"
void MainWindowImpl::startThread()
{
    QString Ln1, Ln1Hex;
    threadA.start();
    Ln1 = QString::fromLocal8Bit("Запущен поток");
    Ln1Hex = threadA.StrA; // Переданная строка из потока. Так ли это????????????
    lbInfo_masA->setText(Ln1);
    lbInfo_masAHex->setText(Ln1Hex);
    if(!threadA.myValue){
        Ln1 = QString::fromLocal8Bit("Передано значение");
        Ln1Hex = threadA.StrVal;
        lbInfo_masB->setText(Ln1);
        lbInfo_masBHex->setText(Ln1Hex);
    }
}


PM MAIL   Вверх
null56
Дата 30.8.2009, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Код

 emit currentValueA(StrA); // Нельзя ли так передать строку главному приложению (потоку)????????????

можно, если у тебя будет соответствующий слот с аргументов QString со стороны главного приложения
Код

Ln1Hex = threadA.StrA; // Переданная строка из потока. Так ли это????????????

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

ЗЫ: у тебя хоть какая  = нибудь книжка есть по Qt? или в ассистенте ты примеры нашел?

PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Правильно ли я понял. Для того чтобы передать приложению из потока строку, я должен написать подобное
void MainWindowImpl::startThread(const QString&). Но этот SLOT на кнопке "Старт" и при этом такая ошибка:
Код

void MainWindowImpl::startThread(const QString&)
src/mainwindowimpl.cpp: In member function ‘void MainWindowImpl::startThread(const QString&)’:
src/mainwindowimpl.cpp:14: ошибка: passing ‘const QString’ as ‘this’ argument of ‘QString& QString::operator=(const QString&)’ discards qualifiers
src/mainwindowimpl.cpp:19: ошибка: passing ‘const QString’ as ‘this’ argument of ‘QString& QString::operator=(const QString&)’ discards qualifiers


Укажите мне пожалуйста, что мне нужно поменять, для того, чтобы увидеть изменяющие строки на главной форме.
Книга есть. Этот пример, но для QDialog, писал по книге. Пример работает. В книге указывалось на асинхронный режим работы Сигнал-Слот для случая Главного потока. Я пишу прогу для работы с COM портом. С использованием QTimer приложение работает. Но требования инженера по железу переписать часть приема/передачи с использованием параллельного потока. Что и пытаюсь понять. Пока с трудом.
PM MAIL   Вверх
andrew_121
Дата 30.8.2009, 19:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодофей
****


Профиль
Группа: Завсегдатай
Сообщений: 3448
Регистрация: 3.1.2008

Репутация: 11
Всего: 33



RobRoj7779, Примитивнейший пример:
Код

class Thread: public QThread {
   Q_OBJECT
public:
   Thread(QObject* o):QThread(o) {
   }
   void run() {
      for ( int idx = 0; idx < 32; ++idx ) {
          emit Update(QString::number(idx));
      }
   }
signals:
   void Update(const QString&);
};

class Form: public QDialog {
   Q_OBJECT
public:
   Form()blabla {
      thread = new Thread(this);
      connect(thread, SIGNAL(Update(const QString&)), line, SLOT(setText(const QString&)));
   }
   Thread *thread;
   QLineEdit *line;
};


Повторяю, это примитивнейший пример!

Добавлено через 1 минуту и 49 секунд
Ты абсолютно не правильно понимаешь работу с потоками, и с QThread в частности. Почитай документацию!


--------------------
Удалил аккаунт. Прощайте!
PM MAIL   Вверх
RobRoj7779
Дата 30.8.2009, 20:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 13.7.2009

Репутация: нет
Всего: нет



Код

class Form: public QDialog {
   Q_OBJECT


Мой код для случая class Form: public QDialog { 
отработал так как мне надо. Я не могу понять, что надо изменить что бы то же самое заработало для приложения созданного как MainWindows 
Сейчас я вижу на главной форме обновленные строки, в том случае, если постоянно нажимаю кнопку "Старт"
Мой пример тестовый, переписывать почти готовое приложение (MainWindows) под QDialog не хотелось бы. Месяц работы в пустую.
Помогите пожалуйста, укажите что и как изменить. Код маленький и в процессе обсуждения я его почти весь выложил
Заранее благодарен за помощь
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0570 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.