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

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

Страниц: 1 2 [3] 4 5   Вниз
  Печать  
Автор Тема: Процесс внутри потока?  (Прочитано 31348 раз)
chron1c
Гость
« Ответ #30 : Март 07, 2012, 11:58 »

Последний вариант гораздо лучше. Но все равно итератор здесь совсем не к месту. У класса ProcessTree есть четкий вход и выход в виде QString, Кто дает ей вход и кто получает выход - решает тот кто создает экземпляр  класса ProcessTree и управляет им, а не сам класс. Поэтому примерно так

Код
C++ (Qt)
#include "processtree.h"
#include <QProcess>
 
ProcessTree::ProcessTree( void ) :  mProcess(0)
{
}
 
ProcessTree::~ProcessTree( void )
{
delete mProcess;
}
 
// void ProcessTree::run()  // не нужно перекрывать
 
// пришел сигнал от запущенного процесса
void ProcessTree::SlotReadProcess( void )
{
       assert(mProcess);
QString output = mProcess->readAllStandardOutput());
delete mProcess;
       mProcess = 0;
 
       emit SignalReply(reply_Output, output);   // ответили боссу
}
 
// пришла команда (от кто создал экземпляр ProcessTree)
void ProcessTree::SlotCommand( int cmd, QString param )
{
       switch (cmd) {
 
          case cmd_GetStatus:
           if (mProcess) emit SignalReply(reply_Busy, "Waiting for process");
           else emit SignalReply(reply_Ready, "Ready");
           break;
 
          case cmd_RunProcess:
           if (mProcess) emit SignalReply(reply_Busy, "Waiting for process");
           else {
             mProcess = new QProcess();
             connect(mProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(slotReadProcess()));
     mProcess->start("cmd /C ping " + param);
             emit SignalReply(reply_Running, "Running");
           }
 
          default:
             emit SignalReply(reply_Error, "Unknown command");
       }
}
 


Вот, как раз то, что хотел увидеть, спасибо! Улыбающийся

Получается, что при
Код:
delete mProcess;
он корректно убивается? Как я понимаю, зря я kill() использовал?
Итератор я использовал т.к. не знал как ещё обращаться к элементам в QTreeWidget.
Получается, что такой экземпляр ProcessTree мне нужно в своём потоке ( в его run() ) создать, соеденить его SignalReply с каким-то слотом в потоке, а в конце прописать exec()?
И в потоке мне нужно будет ловить сигнал SignalReply и, если получен output, то проверять его на "TTL"/менять текст по итератору/высылать команду в SlotCommand, чтоб создавался новый процесс? Хм. Всё равно придётся передавать в поток дерево, например, а чтоб его в потоке постоянно прогонять нужен какой-то цикл, что ли. Или можно зациклить сигналами и слотами просто? ( пытался же, но не получилось ). И опять же, в потоке только итератором мне видится возможным это провернуть.
И ещё есть один вопрос, который мне с трудом дал уснуть сегодня, когда я по указателю соединяю процесс со слотом, то, убив/удалив процесс, а указателю присвоив адрес нового процесаа, будет ли новый процесс соединён так же?
Записан
Bepec
Гость
« Ответ #31 : Март 07, 2012, 12:00 »

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

Насчёт вопроса с сигналом я неуверен, но помоему не будет соединён.
Записан
mutineer
Гость
« Ответ #32 : Март 07, 2012, 12:04 »

И ещё есть один вопрос, который мне с трудом дал уснуть сегодня, когда я по указателю соединяю процесс со слотом, то, убив/удалив процесс, а указателю присвоив адрес нового процесаа, будет ли новый процесс соединён так же?

Без повторного connect не будет
Записан
chron1c
Гость
« Ответ #33 : Март 07, 2012, 12:11 »

У меня просто в дереве у некоторых айтемов есть дети, т.е. уже внуки дерева, и я так и не нашел в доках ( или плохо искал ) как можно поочереди обращаться ко всем QTreeWidgetItem, кроме как через итератор. Приходилось во внутренних переменных хранить адрес на итератор(sic!), чтоб он был в потоке виден не только в run();
Как-то пробовал в QObjectList дёргать детей по findChildren<QTreeWidgetItem *>();, но как-то не очень решением мне это показалось. Или как вариант?
Записан
Bepec
Гость
« Ответ #34 : Март 07, 2012, 12:12 »

Создай в потоке указатель на итератор твой. И потом уже используй-используй-используй.
Записан
mutineer
Гость
« Ответ #35 : Март 07, 2012, 12:16 »

Создай в потоке указатель на итератор твой. И потом уже используй-используй-используй.

Указатель на итератор? а если итератор инвалидируется или уничтожится? Или дерево не меняется?
Записан
chron1c
Гость
« Ответ #36 : Март 07, 2012, 12:23 »

Дерево не меняется, меняются только элементы в нём. Думал, когда итератор будет уже ни на что не показывать, то пересоздавать его, на начало дерева возвращая этим.
Хм, но у меня и был в потоке указатель на итератор. Казалось мне каким-то странным делать так:
Код:
(**iterator)->setText(0, "o.o");
и.т.п., но, если указатель на итератор - это не пример плохого кода, то ок, буду так делать, всё же удобно довольно.
Хм. А когда создаётся итератор, то ему как бы присваивается список возможных значений или как? Просто вот, например, инициализировал я итератор. В конце дерева есть последний элемент, предположим. Итератор до него ещё не добрался, а элемент я удалил и добавил в конец уже новый. Перейдёт ли итератор корректно на него?
Записан
BRE
Гость
« Ответ #37 : Март 07, 2012, 12:32 »

Не нужно передавать в поток никакие итераторы, тем более на элементы связанные с GUI. Чем меньше поток будет знать, тем лучше.
Что ему знать необходимо? - адрес хоста для пингования. Все. Вот и передавай ему этот адрес в строке, а он должен вернуть ответ: пингуется или нет.
Не нужно все пытаться засунуть в один поток.
Записан
chron1c
Гость
« Ответ #38 : Март 07, 2012, 12:38 »

Хм, ок. Но тогда мне в ГУИ потоке нужно будет этим же итератором перебивать в цикле все элементы, высылая по одному в тот поток? Гуи-то не повиснет, можно событиям давать отправляться каждую итерацию, но вот как тогда менять информацию, принадлежащую пингующемуся/не пингующемуся адресу в дереве? Как-то заморачиваться со слотом в главном потоке, в котором нужно будет ещё и к элементу дерева обращаться и следить ещё как-то, чтоб цикл основном не "убежал вперёд", разве комильфо?
Записан
mutineer
Гость
« Ответ #39 : Март 07, 2012, 12:57 »

Дерево не меняется, меняются только элементы в нём.

....

В конце дерева есть последний элемент, предположим. Итератор до него ещё не добрался, а элемент я удалил и добавил в конец уже новый.

Так меняется дерево или нет? в одном ответе две противоречивых фразы
Записан
chron1c
Гость
« Ответ #40 : Март 07, 2012, 13:13 »

Я думал другое имелось ввиду. Сам объект дерева тем же остаётся, а меняются в нём элементы. Только одно дерево будет проверяться.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #41 : Март 07, 2012, 16:05 »

Получается, что при
Код:
delete mProcess;
он корректно убивается?
Вроде в букваре написано что да

И ещё есть один вопрос, который мне с трудом дал уснуть сегодня, когда я по указателю соединяю процесс со слотом, то, убив/удалив процесс, а указателю присвоив адрес нового процесаа, будет ли новый процесс соединён так же?
Нет, не будет, нужно опять соединять

Итератор я использовал т.к. не знал как ещё обращаться к элементам в QTreeWidget.
Получается, что такой экземпляр ProcessTree мне нужно в своём потоке ( в его run() ) создать, соеденить его SignalReply с каким-то слотом в потоке, а в конце прописать exec()?
И в потоке мне нужно будет ловить сигнал SignalReply и, если получен output, то проверять его на "TTL"/менять текст по итератору/высылать команду в SlotCommand, чтоб создавался новый процесс? Хм. Всё равно придётся передавать в поток дерево, например, а чтоб его в потоке постоянно прогонять нужен какой-то цикл, что ли. Или можно зациклить сигналами и слотами просто? ( пытался же, но не получилось ). И опять же, в потоке только итератором мне видится возможным это провернуть.
Создаете ProcessTree один раз напр на старте приложения и удаляете его напр на финише. Если надо обойти дерево, то лучше поручить эту задачу др классу. Можно унаследоваться от QTreeWidgetItemIterator, напр

Код
C++ (Qt)
class CMyIterator : public QTreeWidgetItemIterator {
public
 CMyIterator( ProcessTree * proc, QTreeWidget * tree );
 
signals:
 void SignalFinished( void );  // испускается когда обход закончен
 void SignalError    ( void );  // процесс не смог нормально выполнится
 void SignalNext    ( void );   // посылает ProcessTree след команду
 
slots:
 void SlotReply( int reply, QString txt );   // принимает ответ ProcessTree и переходит на след элемент
};
 
Этот класс спокойно создаете хоть бы и в главной нитке. По SlotReply обновляете UI, в конце-концов получите SignalFinished.

По поводу "зациклить" - в событийной (event-driven) схеме этого нет. Неизвестно сколько времени займет хотя бы запуск процесса, поэтому в любом случае надо выставить значения каких-то переменных и ждать сигнала, продолжая работу с UI и др
« Последнее редактирование: Март 07, 2012, 16:11 от Igors » Записан
chron1c
Гость
« Ответ #42 : Март 10, 2012, 00:24 »

Хм, понятно. Т.е. лучше заставить в доп. потоке висеть процесс и по сигналу запускать и давать вывод, а обрабатывать его уже в главном. Хм, ок, попробую. Хотя с трудом представляется как всё это реализовать. А чем плоха моя идея засунуть вообще всю обработку в доп. поток? Там что-то принципиально не верно, что ли? Я её уже по-всякому мучил, так и не заставил работать.
Попробую сделать как советовал Igors.
Нопочему-то не объявляется класс, унаследованный от итератора.
Хоть я и хочу спать, но раз 5 пересмотрел - вроде всё верно ведь пишу.
Код:
#ifndef TEST_H
#define TEST_H
#include <QTreeWidgetItemIterator>

class QTreeWidget;
class ProcessTree;

class TreeIterator : public QTreeWidgetItemIterator
{
Q_OBJECT
public:
TreeIterator(ProcessTree *proc, QTreeWidget *tree);
signals:
void signalFinished();
void signalError();
void signalNext();
public slots:
    void slotReply(int reply, QString txt );
private:
ProcessTree *process;
QTreeWidget *tree;
};

#endif

Компилятор выдаёт:
Код:
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(11) : error C2143: syntax error : missing ';' before 'public'
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(11) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(14) : error C2062: type 'void' unexpected
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(14) : error C2238: unexpected token(s) preceding ';'
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(17) : error C2146: syntax error : missing ':' before identifier 'slots'
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(18) : error C2062: type 'void' unexpected
1>c:\qtsdk\myprojects\myapplication\myapplication\generatedfiles\debug\../../test.h(18) : error C2238: unexpected token(s) preceding ';'
1>.\GeneratedFiles\Debug\moc_test.cpp(12) : fatal error C1189: #error :  "The header file 'test.h' doesn't include <QObject>."

Пробовал включать QObject туда, тогда получаю:
Код:
1>.\GeneratedFiles\Debug\moc_test.cpp(51) : error C2039: 'staticMetaObject' : is not a member of 'QTreeWidgetItemIterator'
1>        c:\qt\4.6.3\include\qtgui\../../src/gui/itemviews/qtreewidgetitemiterator.h(62) : see declaration of 'QTreeWidgetItemIterator'
1>.\GeneratedFiles\Debug\moc_test.cpp(61) : error C2227: left of '->metaObject' must point to class/struct/union/generic type
1>.\GeneratedFiles\Debug\moc_test.cpp(61) : error C2227: left of '->metaObject' must point to class/struct/union/generic type
1>.\GeneratedFiles\Debug\moc_test.cpp(69) : error C2039: 'qt_metacast' : is not a member of 'QTreeWidgetItemIterator'
1>        c:\qt\4.6.3\include\qtgui\../../src/gui/itemviews/qtreewidgetitemiterator.h(62) : see declaration of 'QTreeWidgetItemIterator'
1>.\GeneratedFiles\Debug\moc_test.cpp(74) : error C2039: 'qt_metacall' : is not a member of 'QTreeWidgetItemIterator'
1>        c:\qt\4.6.3\include\qtgui\../../src/gui/itemviews/qtreewidgetitemiterator.h(62) : see declaration of 'QTreeWidgetItemIterator'
1>.\GeneratedFiles\Debug\moc_test.cpp(93) : error C2665: 'QMetaObject::activate' : none of the 4 overloads could convert all the argument types
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(346): could be 'void QMetaObject::activate(QObject *,int,int,void **)'
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(347): or       'void QMetaObject::activate(QObject *,const QMetaObject *,int,void **)'
1>        while trying to match the argument list '(TreeIterator *const , const QMetaObject *, int, int)'
1>.\GeneratedFiles\Debug\moc_test.cpp(99) : error C2665: 'QMetaObject::activate' : none of the 4 overloads could convert all the argument types
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(346): could be 'void QMetaObject::activate(QObject *,int,int,void **)'
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(347): or       'void QMetaObject::activate(QObject *,const QMetaObject *,int,void **)'
1>        while trying to match the argument list '(TreeIterator *const , const QMetaObject *, int, int)'
1>.\GeneratedFiles\Debug\moc_test.cpp(105) : error C2665: 'QMetaObject::activate' : none of the 4 overloads could convert all the argument types
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(346): could be 'void QMetaObject::activate(QObject *,int,int,void **)'
1>        c:\qt\4.6.3\include\qtcore\../../src/corelib/kernel/qobjectdefs.h(347): or       'void QMetaObject::activate(QObject *,const QMetaObject *,int,void **)'
1>        while trying to match the argument list '(TreeIterator *const , const QMetaObject *, int, int)'

В данный момент вникаю в вывод компилятора. Подозреваю, что итератор нельзя наследовать вообще.
Записан
BRE
Гость
« Ответ #43 : Март 10, 2012, 08:48 »

Итератор это небольшой инструментальный класс, объекты которого, позволяют выполнять навигацию по контейнеру. Все. Пытаться запихнуть туда еще "кучу важных дел" глупо. Это как к строительному мастерку прикрутить метровый уровень - получиться новый инструмент, только делать с ним уже ничего не захочется. Улыбающийся
Я бы использовал пул потоков + очередь, для хранения адресов хостов (темы где есть работающие примеры на форуме есть), но если хочешь через сигналы-слоты, то сделай класс-менеджер заданий наследником QObject, а уже внутри используй QTreeWidgetItemIterator.

И да, самое простое решение это воспользоваться QtConcurrent. Можно все сделать в несколько строк.
« Последнее редактирование: Март 10, 2012, 10:40 от BRE » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #44 : Март 10, 2012, 13:04 »

А чем плоха моя идея засунуть вообще всю обработку в доп. поток? Там что-то принципиально не верно, что ли?
Смотрите какие есть связки/зависимости. Запуск процесса у Вас связан с итератором дерева. Эта конструкция не имеет никакой гибкости. Потребуется обойти напр таблицу - и что, весь запуск процесса опять писать?  Также передача данных (асинхронка) в нитку обходится гораздо дороже - и по написанию, и по времени выполнения. Всегда лучше вынести из нитки все что можно.

Попробую сделать как советовал Igors.
Нопочему-то не объявляется класс, унаследованный от итератора.
Ну с наследованием я переборщил - наследование от итератора + QObject явно "не то". Так передайте итератор по ссылке
Код
C++ (Qt)
class TreeIterator : public QObject
{
Q_OBJECT
public:
TreeIterator(ProcessTree *proc, QTreeWidgetIteraor & iter);
 
...
private:
ProcessTree * mProcess;
QTreeWidgetIterator & mIterator;
};
 
"альтернатива наследование/членство"

Итератор это небольшой инструментальный класс, объекты которого, позволяют выполнять навигацию по контейнеру. Все. Пытаться запихнуть туда еще "кучу важных дел" глупо. Это как к строительному мастерку прикрутить метровый уровень - получиться новый инструмент, только делать с ним уже ничего не захочется. Улыбающийся
Операция может быть и сложной, но если она применяется только к элементу - по смыслу это итерирование. Но согласен, раздувать класс итератора ни к чему.

Я бы использовал пул потоков + очередь, для хранения адресов хостов (темы где есть работающие примеры на форуме есть), но если хочешь через сигналы-слоты, то сделай класс-менеджер заданий наследником QObject, а уже внутри используй QTreeWidgetItemIterator.

И да, самое простое решение это воспользоваться QtConcurrent. Можно все сделать в несколько строк.
Не уверен насчет QtConcurrent, как я понял, процесс должен запускаться снова по окончанию предыдущего - нужно последовательное, а не параллельное выполнение. Через очередь - это уже др задача/функционал. Разница видна напр если дерево меняется динамически (пока идет опрос адресов)
« Последнее редактирование: Март 10, 2012, 13:07 от Igors » Записан
Страниц: 1 2 [3] 4 5   Вверх
  Печать  
 
Перейти в:  


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