Russian Qt Forum

Qt => Общие вопросы => Тема начата: chron1c от Март 06, 2012, 01:21



Название: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 01:21
Доброго времени суток.
Собственно, проблема:
Есть класс для процесса и для потока.
Класс потока:
Код:
//========== processtree.h
class ProcessTree : public QThread
{
        Q_OBJECT
public:
        void setTree(QTreeWidget *i);
protected:
        QTreeWidget *tree;
        void run();
private:
        bool checkPing(const QString *str);
};
//======== processtree.cpp
void ProcessTree::run()
{
        QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
        MyShell *test = new MyShell;
        test->start(*iterator);
}
 
void ProcessTree::setTree(QTreeWidget *item, MyShell *p)
{
        tree = item;
}


Через setTree принимает указатель на QtreeWidget, в своей переменной запоминает его.
Далее создаётся итератор и в процесс передаётся указатель на QTreeWidgetItem. Итератор создаю, т.к. потом планирую по очереди каждый QTreeWidgetItem в tree перебрать. ( вообще, нужно проверить пингуется ли комп, айпишник которого лежит в text(0) в каждом QTreeWidgetItem.

Класс процесса:

Код:
//=========== H
class MyShell : public QProcess {
Q_OBJECT
signals:
        void pFinished(bool result);
public:
        MyShell(QWidget *pwgt = 0);
        void start(QTreeWidgetItem *i);
public slots:
        void slotDataOnStdout();
private slots:
        void finalize(bool result);
private:
        QProcess *m_process;
        QTreeWidgetItem *item;
};
//============= CPP
MyShell::MyShell(QWidget *pwgt) : QProcess(pwgt)
{
        item = 0;
        m_process = new QProcess(this);
        connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(slotDataOnStdout()));
        connect(this, SIGNAL(pFinished(bool)), SLOT(finalize(bool)));
}
 
void MyShell::start(QTreeWidgetItem *i)
{
        item = i;
        item->setText(1, "Started");
        m_process->start("cmd /C ping "+item->text(0));
}
 
void MyShell::slotDataOnStdout()
{
                item->setText(1, "inSTD"); //Это просто проверка, получен ли сигнал
                QString *output = new QString(m_process->readAllStandardOutput());
                if(output->indexOf("TTL") < 0) emit finished(false);
                else emit pFinished(true);
/*Здесь ещё раньше ставил m_process->kill(), т.к. пингуется ли айпи можно понять по первой строчке вывда, а ждать, если не пингуется, пока выведет все "Превышен ..." не хочется. Расчитывал убивать процесс, а потом, в цикле в потоке, запускать его снова. Не знаю уж, нормально это или быдлокод, с потоками и процессами первый раз столкнулся. Посоветуете, может, что-нибудь? */
}
 
void MyShell::finalize(bool result)
{
        if(result) item->setText(0, "OWNED!!!"); //Опять проверка
        else item->setText(0, "FAIL :(");
}


По каким-то причинам процесс не высылает readyReadStandardOutput(), ну или его не получает slotDataOnStdout(). Пробовал в главном потоке процесс создавать и родителем его делать QWidget, а не QProcess ( в примере, по которому учился он был с ГУИ и с родителем QWidget ), но тогда придётся заморачиваться с сигналами и слотами между потоками, да и вообще мне как-то сложно представить как тогда задачу свою решить.
Может, можно и как-нибудь иначе сделать то, что мне нужно, но с Qt я работаю буквально пару дней, так что, естественно, многого не знаю.


Название: Re: Процесс внутри потока?
Отправлено: neversleep от Март 06, 2012, 05:33
Зачем вообще парится с процессом? Юзай винапи ф-цию IcmpSendEcho (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366050%28v=vs.85%29.aspx) или т.н raw sockets.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 11:57
Я в этом понимаю ещё меньше, чем в Qt, т.е. вообще ничего :)
По ТЗ нужно сделать именно на Qt, да и уже просто интересно почему в моём случае не работает. Столько провозился и времени столько потерял, что теперь, не разобравшись, забивать как-то не хочется.


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 12:02
минимально компилируемый проект в архив и в студию.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 12:57
Комментарии внутри.
Чуть не забыл, пишу его в VS2008 с Add-In'ом Qt4.6.


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 13:21
Отвечаю - интересная реализация конечно потоков...

Первое
Тебя не насторожили надписи в Output

Код:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0xa7bd18), parent's thread is QThread(0x3e9270), current thread is ProcessTree(0x12fec8)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0xa7bd18), parent's thread is QThread(0x3e9270), current thread is ProcessTree(0x12fec8)

Которые вылетают на строчке

Код:
m_process->start("cmd /C ping "+item->text(0));


Мораль - ты создаёшь QProcess в 1 потоке, а потом пытаешься запустить во втором...Он и сопротивляется.

Второе
Очень интересная реализация потоков.

Код:
void ProcessTree::run()
{
/* -//-//-//-
*/
QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
process->start(*iterator);
           // А вот тут, после выполнения 1 функции start, поток умирает, если не вызвать к примеру QThread::run();
}

А по делу - читай про потоки, делай простенькие программки. Они тебе не будут терпеливо ждать, пока придёт ответ, выполнится QProcess. Он до конца run дойдёт и на кладбище.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 13:43
На самом деле я даже не знаю как в этот Output заглянуть. С VS столько же, сколько и с Qt знаком. Раньше в блокноте писал всё.
Передавать адрес процесса я только сейчас стал, до этого было в ProcessTree:
Код:
	MyShell *test = new MyShell;
QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
test->start(*iterator);
И родителем у MyShell был QProcess, а не QWidget. (Если ставить QWidget, то ругается, что виджеты должны в ГУИ-потоке запускаться. )

После
Код:
process->start(*iterator);
думал, может, ставить
Код:
sleep(2);
или что-то такое, хоть корректным мне это и не кажется.
Как-то ведь можно поток заставить ждать пока не придёт сигнал от процесса? Так думал поступить. Ну и как в комментариях написал, то в теле run() хотел ставить бесконечный цикл, просто сейчас его там нет, т.к. на одном элементе даже не работает схема.

Интересная реализация, если с профессиональной точки зрения, то это, скорее, в плохом или хорошем смысле?


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 13:55
Я бы сказал честно - в отвратительном :)

Понамешано всего(хотя понятно, новичок всё же).

А ты не пробовал к примеру создавать QProcess динамически внутри потока. И до тех пор, пока поток не обработает все NNN адресов, его не отпускать на кладбище?


Набросок на мой (возможно не оч профессиональный) взгляд:

Создаётся виджет, заполняется таблица с IP.

После чего тыкается кнопка и запускается поток. Поток каждый раз создаёт QProcess, ждёт его завершения и результатов, переходит к следующему. Как только адреса заканчиваются - заканчивается цикл и поток умирает. До тех пор, пока кто-то добрый не нажмёт кнопочку и снова не создаст экземпляр потока.


PS программа на 8,000-12,000 строк в блокноте, это, конечно, сильно.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 14:00
Ну я именно так и хочу сделать. Процесс оказался в главном потоке только потому, что я проверял, будет ли хоть так работать. Как и выше написал, сейчас у меня так:
Код:
void ProcessTree::run()
{
MyShell *test = new MyShell; // <- Это разве не динамически создаётся?
QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
test->start(*iterator);
        /* Ну а здесь проверка на завершился ли процесс будет, а сейчас хоть бы для одного элемента заставить работать его. */
}


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 14:09
ну вызови ты в конце концов QThread::run();
Код:
void ProcessTree::run()
{
MyShell *test = new MyShell; // <- Это разве не динамически создаётся?
QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
test->start(*iterator);
        /* Ну а здесь проверка на завершился ли процесс будет, а сейчас хоть бы для одного элемента заставить работать его. */
            QThread::run();
}


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 14:46
О мой бог, как же я затупил. Спасибо!
Только сейчас дошло, что поток, завершившись, убивает и процесс, который просто не успевает завершиться.
Как я понимаю, поставив в конец run() - я зациклю поток. Но как заставить его перебирать итераторы? Хм. Почитал в ассистенте про QThread::run(), так и не понял, почему, поставив его в конец, всё заработало. У родителя( QThread ) не переопределён у меня же run(), => вызовется QThread::exec()? В доках написано, что он буде ждать, пока не получит exit(), но от кого он будет его ждать? И когда будет выслан exit()? Когда завершится процесс внутри ProcessTree?


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 14:54
QThread::run() делает поток "событийным", реагирующим только на вызовы извне и сигналы. Сам же он ждёт тихо тихо.

А exit() ему надо передавать самому(я так делаю, ибо потоки у меня опасные ;) ).

Если же не вызывать run(), а зациклить на пустой цикл, то поток будет жрать память не по деццки. (Дурью маяться тяжелооо... Вот и будет йхенй страдать ;) )

ПОПРАВКА - зациклить на пустой цикл аля
Код:
while(true)
{}



Название: Re: Процесс внутри потока?
Отправлено: BRE от Март 06, 2012, 15:08
Если же не вызывать run(), а зациклить на пустой цикл, то поток будет жрать память не по деццки.
;D Ты откуда это берешь? Почему он будет память жрать?


Название: Re: Процесс внутри потока?
Отправлено: LisandreL от Март 06, 2012, 15:08
Если же не вызывать run(), а зациклить на пустой цикл, то поток будет жрать память не по деццки. (Дурью маяться тяжелооо... Вот и будет йхенй страдать
Память? С чего бы ему память-то потреблять? У вас она течёт где-то?
Может вы загрузку процессора имели в виду?


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 15:12
вру вру ) Процессорное время ;)

Точнее даже не всего процессора, а 1 ядро ;)


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 15:22
Можно ведь в цикле в потоке написать sleep(<n>), тогда не будет же зря память/процессорное время есть?
Код:
void ProcessTree::run()
{
MyShell *test = new MyShell;
//QTreeWidgetItemIterator iterator(tree, QTreeWidgetItemIterator::All);
(*iterator)->setText(1, "YO!"); //проверка
sleep(3);
test->start(*iterator); //не успевает процесс выполниться, только на половину
run(); //Вот так поток циклится
}
Несколько вопросов возникает:
Когда будет освобождена память, выделенная для MyShell в самом начале? (глупый вопрос, возможно, но я пока в таких делах плохо ориентируюсь ).
Ну и нужно ли делать в конце цикла
Код:
delete test;
или автоматически всё же освободится?

Всё ещё не до конца понял про QThread::run();
Как можно это использовать, чтоб успевал выполниться MyShell и только потом инкрементировался итератор и выполнялся run()?

Каким-то образом нужно ещё хранить итератор этот, чтоб определять его не в run(), а то будет сбрасываться на начало каждый раз. Или лучше циклить всё это через for(;;) или аналог?
Извините за, возможно, сумбурное изложение, болею и всё это время сижу над программой, могу на ровном месте уже тупить.


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 15:30
Вам бы книжечку почитать :D Шлее.

Про сигналы и слоты. Про потоки.

Так же Страуструпика про выделение памяти...

Когда вы sleep(n) делаете, поток у вас засыпаеть намертво. И ему будет до фени все ваши командоссы на n времени ;)

А если функционал программы расширится, тогда вообще мрак будет ;)


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 15:40
Ну, я знаю, что замирает намертво при sleep(), поэтому и пишу его. Это так, чтоб успеть увидеть изменения.
Шлее как раз открыт сейчас. Просто я подзабыл, освобождается ли память автоматически в Qt :)
P.S: раньше у меня не было отдельного класса для процесса, а было всё в потоке определено, но когда запутался, то сделал так, как есть сейчас. Как думаете, имеет ли смысл все сигналы и слоты у потока реализовывать и не использовать свой класс для процесса?


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 15:46
Мой ответ - я использую поток как отдельный класс. Проще говоря, поток каждого типа выполняет свои ф-ции. Как бы так оно яснее, наглядней и проще для отладки/реализации.

Конечно же чуть труднее для переноса класса, но... Все операции которые я делаю потоками, НЕ ПОТОКАМИ делать невыгодно ;)


Название: Re: Процесс внутри потока?
Отправлено: neversleep от Март 06, 2012, 16:46
Зато как красиво... ::)
Код
C++ (Qt)
#ifndef DIALOG_H
#define DIALOG_H
 
#include <QDialog>
#include <QThread>
 
namespace Ui {
class Dialog;
}
 
class Dialog : public QDialog
{
   Q_OBJECT
 
public:
   explicit Dialog(QWidget *parent = 0);
   ~Dialog();
 
private:
   Ui::Dialog *ui;
 
private slots:
   void pinged(const QString &ip, bool success);
};
 
class Pinger: public QThread
{
   Q_OBJECT
 
public:
   Pinger(QObject *parent = 0):
       QThread(parent)
   {
   }
 
   void ping(const QStringList &ips, const unsigned int timeout);
 
private:
   QStringList addrs;
   unsigned int timeout;
 
protected:
   void run();
 
signals:
   void pinged(const QString &ip, bool success);
};
 
#endif // DIALOG_H
 

Код
C++ (Qt)
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
 
#ifdef Q_OS_WIN
# include <WinSock2.h>
# include <IPHlpApi.h>
# include <IcmpAPI.h>
#endif
 
#ifdef _MSC_VER
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "iphlpapi.lib")
#endif
 
Dialog::Dialog(QWidget *parent) :
   QDialog(parent),
   ui(new Ui::Dialog)
{
   ui->setupUi(this);
 
   Pinger *pinger = new Pinger;
   connect(pinger, SIGNAL(finished()), pinger, SLOT(deleteLater()));
   connect(pinger, SIGNAL(pinged(QString,bool)), this, SLOT(pinged(QString,bool)));
   pinger->ping(QStringList() << "192.168.0.1" << "192.168.0.5" << "87.118.94.143", 1000);
}
 
Dialog::~Dialog()
{
   delete ui;
}
 
void Dialog::pinged(const QString &ip, bool success)
{
   qDebug() << ip << success;
}
 
void Pinger::ping(const QStringList &ips, const unsigned int timeout)
{
   if (!isRunning()) {
       this->addrs = ips;
       this->timeout = timeout;
 
       start();
   }
}
 
void Pinger::run()
{
#ifdef Q_OS_WIN
   HANDLE hIcmpFile = IcmpCreateFile();
   if (hIcmpFile != INVALID_HANDLE_VALUE) {
       char RequestData[] = "ping";
       DWORD ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(RequestData);
       char *ReplyBuffer = new char[ReplySize];
 
       for (int i = 0, count = addrs.count(); i < count; i++) {
           bool success = false;
           const QString ip = addrs.at(i);
           const int addr = inet_addr(ip.toAscii().data());
           if (addr != INADDR_NONE) {
               if (IcmpSendEcho(hIcmpFile, addr, RequestData, sizeof(RequestData), 0, ReplyBuffer, ReplySize, timeout) != 0) {
                   PICMP_ECHO_REPLY icmpReply = (PICMP_ECHO_REPLY)ReplyBuffer;
                   success = icmpReply->Status == IP_SUCCESS;
               }
           }
 
           emit pinged(ip, success);
       }
       delete []ReplyBuffer;
       IcmpCloseHandle(hIcmpFile);
       exit(0);
   }
#endif
   exit(-1);
}
 


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 06, 2012, 17:17
Вау, спасибо, но это же WinAPI? Не хочется использовать код, в котором ничего не понимаю :) Самому как-то хочется сделать всё.
Из всех моих вопросов ответили только на несколько, жаль.

Может кто-нибудь разъяснить как для дурака?
Предположим, напишу я в потоке QThread::run(), что случится-то? В каком смысле он будет реагировать только на сигналы и вызовы извне? Или он тогда просто не завершится, пока я в нём самом не напишу exit()? Но если мне нужно в цикле итератор увеличивать и ждать каждый раз, пока выполнится процесс, то, что, мне нужно в главном потоке каждый раз перезапускать этот поток?



Название: Re: Процесс внутри потока?
Отправлено: VozaMFC от Март 06, 2012, 17:32
Предположим, напишу я в потоке QThread::run(), что случится-то? В каком смысле он будет реагировать только на сигналы и вызовы извне? Или он тогда просто не завершится, пока я в нём самом не напишу exit()? Но если мне нужно в цикле итератор увеличивать и ждать каждый раз, пока выполнится процесс, то, что, мне нужно в главном потоке каждый раз перезапускать этот поток?
Все таки почитай книгу Шлее о взаимодействии потока с главным посредством сигналов...


Название: Re: Процесс внутри потока?
Отправлено: lolbla2 от Март 06, 2012, 19:22
Предположим, напишу я в потоке QThread::run(), что случится-то? В каком смысле он будет реагировать только на сигналы и вызовы извне? Или он тогда просто не завершится, пока я в нём самом не напишу exit()? Но если мне нужно в цикле итератор увеличивать и ждать каждый раз, пока выполнится процесс, то, что, мне нужно в главном потоке каждый раз перезапускать этот поток?
Все таки почитай книгу Шлее о взаимодействии потока с главным посредством сигналов...

Отправляют на книжки или на гугл только те, кому лень объяснить человеку, ведь Вы даже не можете себе представить что человеку проще понять Ваши объяснения в пару строчек, чем читать какую-то огромную статью или даже книгу.

P.S. QThread::run() вызывает run класса QThread, которая по умолчанию, определена в классе как:

Код
C++ (Qt)
run()
{
exec() // запускаем  цикл обработки событий, так называемый QEventLoop, то есть класс может принимать сигналы из "внешнего мира"  
}
 


Поправьте если где ошибся


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 06, 2012, 20:07
Отправляют на книжки или на гугл только те, кому лень объяснить человеку, ведь Вы даже не можете себе представить что человеку проще понять Ваши объяснения в пару строчек, чем читать какую-то огромную статью или даже книгу.

Конечно лень объяснять 50му по счету человеку который не умеет или ленится читать


Название: Re: Процесс внутри потока?
Отправлено: neversleep от Март 06, 2012, 20:57
Вау, спасибо, но это же WinAPI? Не хочется использовать код, в котором ничего не понимаю :) Самому как-то хочется сделать всё.
Ну да, а использовать чужой процесс куда проще и понятней :) Вспомнился один забавный вопрос:
Цитата: управление внешними программами
всем прива
Хотелось бы чтоб моё приложение
1. открыла калькулятор (сделал уже)
2. набрала цыфры (попа ничего не выходит)
3. получив ответ закрыла бы калькулятор(сделал уже)

УЖЕ НАШОЛ ИМИТАЦИЮ КЛАВИШ ЩАС ИМИТАЦИЯ МЫШИ НУЖНА :)
http://www.delphimaster.ru/nuts/nuts.html


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 06, 2012, 22:29
neversleep - как бы ваше предложение интересно, но немного не в тему.

Человек хочет сделать это на Qt, вот и задал вопрос на форуме Qt.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 07, 2012, 02:18
Господа, можете мне опять указать, где я облажался?
Шлее прочитал, но всё равно что-то не то.
Код:
#include "processtree.h"
#include <QTreeWidget>
#include <QTreeWidgetItemIterator>
#include <QProcess>

void ProcessTree::run()
{
iterator = new QTreeWidgetItemIterator(tree, QTreeWidgetItemIterator::All);
process = new QProcess;
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(takeOutput()));
connect(this, SIGNAL(pingResult(bool)), this, SLOT(finalize(bool)));
connect(this, SIGNAL(requestNext()), this, SLOT(processNext()));
process->start("cmd /C ping "+(**iterator)->text(0));
exec();
}

void ProcessTree::setTree(QTreeWidget *item)
{
tree = item;
}

void ProcessTree::takeOutput()
{
QString *output = new QString(process->readAllStandardOutput());
process->kill();
if(output->indexOf("TTL") > 0) emit pingResult(true);
else emit pingResult(false);
delete output;
}

void ProcessTree::finalize(bool result)
{
/* Заморочки с базой и.т.п. будут здесь */
if(result) (**iterator)->setText(1, "OK!");
else (**iterator)->setText(1, "FAIL :(");
emit requestNext();
}

void ProcessTree::processNext()
{
if(**iterator){
++(*iterator);
process->start("cmd /C ping "+(**iterator)->text(0));
} else exit(0);
}

Указатель на итератор кажется мне бредом, но каким ещё образом это можно реализовать я пока не знаю.
По логике всё должно работать, но на деле опять всё не так, как хотелось бы.
Хотел бы увидеть дельных ответов с подробными пояснениями где и почему я дурак, и как лучше сделать, а не читай@гугли, буду очень признателен.


Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 07, 2012, 03:44
Последний вариант гораздо лучше. Но все равно итератор здесь совсем не к месту. У класса 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");
       }
}
 


Название: Re: Процесс внутри потока?
Отправлено: neversleep от Март 07, 2012, 05:07
neversleep - как бы ваше предложение интересно, но немного не в тему.

Человек хочет сделать это на Qt, вот и задал вопрос на форуме Qt.
Я как бы не навязываюсь, и если мой подход идёт вразрез с Qt`шным, то ваша правда, давайте и дальше компенсировать недостатки фреймворка чужими программами.


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 07, 2012, 06:54
neversleep, Человек просто не умеет пока обращаться с потоками. Таки дадим ему возможность научиться???

Причём потоки Qt не являются недостатком. А скорее просто - одним из инструментов, которым надо овладеть. Как и другие ему аналогичные потоки.(boost например)


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 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, чтоб создавался новый процесс? Хм. Всё равно придётся передавать в поток дерево, например, а чтоб его в потоке постоянно прогонять нужен какой-то цикл, что ли. Или можно зациклить сигналами и слотами просто? ( пытался же, но не получилось ). И опять же, в потоке только итератором мне видится возможным это провернуть.
И ещё есть один вопрос, который мне с трудом дал уснуть сегодня, когда я по указателю соединяю процесс со слотом, то, убив/удалив процесс, а указателю присвоив адрес нового процесаа, будет ли новый процесс соединён так же?


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 07, 2012, 12:00
Если у тебя есть указатель на дерево в потоке, то ты можешь делать с деревом всё, что пожелаешь. От убиения дерева, до постройки из него домика.

Насчёт вопроса с сигналом я неуверен, но помоему не будет соединён.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 07, 2012, 12:04
И ещё есть один вопрос, который мне с трудом дал уснуть сегодня, когда я по указателю соединяю процесс со слотом, то, убив/удалив процесс, а указателю присвоив адрес нового процесаа, будет ли новый процесс соединён так же?

Без повторного connect не будет


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


Название: Re: Процесс внутри потока?
Отправлено: Bepec от Март 07, 2012, 12:12
Создай в потоке указатель на итератор твой. И потом уже используй-используй-используй.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 07, 2012, 12:16
Создай в потоке указатель на итератор твой. И потом уже используй-используй-используй.

Указатель на итератор? а если итератор инвалидируется или уничтожится? Или дерево не меняется?


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


Название: Re: Процесс внутри потока?
Отправлено: BRE от Март 07, 2012, 12:32
Не нужно передавать в поток никакие итераторы, тем более на элементы связанные с GUI. Чем меньше поток будет знать, тем лучше.
Что ему знать необходимо? - адрес хоста для пингования. Все. Вот и передавай ему этот адрес в строке, а он должен вернуть ответ: пингуется или нет.
Не нужно все пытаться засунуть в один поток.


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


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 07, 2012, 12:57
Дерево не меняется, меняются только элементы в нём.

....

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

Так меняется дерево или нет? в одном ответе две противоречивых фразы


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 07, 2012, 13:13
Я думал другое имелось ввиду. Сам объект дерева тем же остаётся, а меняются в нём элементы. Только одно дерево будет проверяться.


Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 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 и др


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 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)'

В данный момент вникаю в вывод компилятора. Подозреваю, что итератор нельзя наследовать вообще.


Название: Re: Процесс внутри потока?
Отправлено: BRE от Март 10, 2012, 08:48
Итератор это небольшой инструментальный класс, объекты которого, позволяют выполнять навигацию по контейнеру. Все. Пытаться запихнуть туда еще "кучу важных дел" глупо. Это как к строительному мастерку прикрутить метровый уровень - получиться новый инструмент, только делать с ним уже ничего не захочется. :)
Я бы использовал пул потоков + очередь, для хранения адресов хостов (темы где есть работающие примеры на форуме есть), но если хочешь через сигналы-слоты, то сделай класс-менеджер заданий наследником QObject, а уже внутри используй QTreeWidgetItemIterator.

И да, самое простое решение это воспользоваться QtConcurrent. Можно все сделать в несколько строк.


Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 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, как я понял, процесс должен запускаться снова по окончанию предыдущего - нужно последовательное, а не параллельное выполнение. Через очередь - это уже др задача/функционал. Разница видна напр если дерево меняется динамически (пока идет опрос адресов)


Название: Re: Процесс внутри потока?
Отправлено: BRE от Март 10, 2012, 13:10
процесс должен запускаться снова по окончанию предыдущего
Можно легко перезапускать.

нужно последовательное, а не параллельное выполнение.
Что-то мне подсказывает что это не так. Для чего тогда использовать потоки?



Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 10, 2012, 13:23
нужно последовательное, а не параллельное выполнение.
Что-то мне подсказывает что это не так. Для чего тогда использовать потоки?
Ну это вопрос к chron1c :) Я понял что опрос адресов выполнять в отдельной нитке - чтобы UI не замерзало, разумно. А натравить N ниток на все адреса - разговора не было.


Название: Re: Процесс внутри потока?
Отправлено: BRE от Март 10, 2012, 13:32
Ну это вопрос к chron1c :)
Согласен. :)

Я понял что опрос адресов выполнять в отдельной нитке - чтобы UI не замерзало, разумно.
Ну как бы QProcess прекрасно работает асинхронно, совсем не замораживая UI.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 10, 2012, 23:06
Дело не только в QProcess, нужно постоянно работать с элементами дерева, один за другим. И элементы будут удаляться/изменяться/добавляться. К тому же, далее планируется расширение программы ещё одним функционалом, поэтому в главном потоке хочется оставить минимум.
Гибкость, хм. Да, соглашусь с вами, хоть она мне тут и не нужна, но лишней не будет. Сделаю чтоб класс принимал QString.
В идеале, сделать бы в потоке просто цикл бесконечный, который продолжался бы переходил на следующую итерацию только после того как получит сигнал определённый. А когда итератор бы начинал указывать ни на что, то просто его пересоздавать, заставляя тем самым указывать на начало дерева снова. Сделать "бесконечный цикл" только сигналами и слотами представляется мне нереализуемым, т.к. сколько бы я не пытался, даже если по логике всё корректно, то не работало ничего.


Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 11, 2012, 10:36
В идеале, сделать бы в потоке просто цикл бесконечный, который продолжался бы переходил на следующую итерацию только после того как получит сигнал определённый. А когда итератор бы начинал указывать ни на что, то просто его пересоздавать, заставляя тем самым указывать на начало дерева снова.
Тогда передавайте во второй класс указатель на дерево а итератор делайте членом этого класса. В слоте SlotRеply присваиваете ему новый итератор как только старый закончился. Сделав второй маленький класс мы развязали себе руки, его легко менять как угодно, в этом гибкость.

Сделать "бесконечный цикл" только сигналами и слотами представляется мне нереализуемым, т.к. сколько бы я не пытался, даже если по логике всё корректно, то не работало ничего.
Все прекрасно получается если "бесконечный цикл" заменить на "бесконечный обмен сигналами"  :)

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


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 12, 2012, 20:38
Хм. Попробовал так:
Код:
#include "pingstring.h"
#include <QProcess>
PingString::PingString()
{
mProcess = 0;
}

void PingString::takeOutput()
{
QString *output = new QString(mProcess->readAllStandardOutput());
        mProcess->kill();
        //delete mProcess;
bool result = false;
if(output->contains("TTL")) result = true;
delete output;
emit pingResult(result);
}

void PingString::pingAdress(const QString &text)
{
mProcess = new QProcess;
connect(mProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(takeOutput()));
mProcess->start("cmd /C ping "+(text));
}
Код:
#include "iplistiterator.h"
#include <QTreeWidget>
#include <QTreeWidgetItemIterator>

IplistIterator::IplistIterator(QTreeWidget *pTree, QObject *parent) : QObject(parent)
{
tree = pTree;
iterator = new QTreeWidgetItemIterator(tree, QTreeWidgetItemIterator::All);
}

void IplistIterator::finalize(bool result)
{
/* Заморочки с базой и.т.п. будут здесь */
if(result) (**iterator)->setText(1, "OK!");
else (**iterator)->setText(1, "FAIL :(");
++(*iterator);
if(!(**iterator)) { delete iterator; iterator = new QTreeWidgetItemIterator(tree, QTreeWidgetItemIterator::All); }
emit nextPlease((**iterator)->text(0));
}

void IplistIterator::start()
{
emit nextPlease((**iterator)->text(0));
}
Код:
#include "pingthread.h"
#include "iplistiterator.h"
#include "pingstring.h"
#include <QThread>
#include <QTreeWidget>

PingThread::PingThread(QTreeWidget *pTree)
{
tree = pTree;
}

void PingThread::run()
{
PingString *pingString = new PingString;
IplistIterator *iplistIterator = new IplistIterator(tree);

connect(pingString, SIGNAL(pingResult(bool)), iplistIterator, SLOT(finalize(bool)));
connect(iplistIterator, SIGNAL(nextPlease(const QString &)), pingString, SLOT(pingAdress(const QString &)));

iplistIterator->start();
exec();
}

delete mProcess; закомментирован, т.к. по каким-то причинам, если удалять процесс, то крашится программа, даже если перед этим его ->kill()/->terminate()
Ещё, что странно, но объекта в дереве( их пока 2) присваивается результат первого проверенного. Не могу понять почему, по логике ведь всё правильно.
По элементам в дереве бегает всё исправно, даже когда удаляю/добавляю элементы новые. Быстро слишком, но думаю просто передать указатель на родитель в PingString и слипать его в начале pingAdress. Но это всё потом, когда заставлю работать нормально.
Совершенно не понимаю почему всё работает так, будто output не удаляется с первой итерации. Там ведь стоит delete output. Опять я в тупике.
И, как я понимаю, если не удалять процесс, то будет утечка памяти, но почему всё же крашится, если удалять?
Опять прошу более опытных товарищей воздержаться от поучений и отправок в гугл/книгу, я осознаю, что я новичок и знаю мало, поэтому я и здесь. Пробую, пытаюсь разобраться.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 12, 2012, 21:51
Разобрался с аутпутом, всё работает корректно, это я опять затупил. Ставил первым адресом на проверку непингущийся, а вторым - пингующийся. Во втором один нолик перепутал :)
Вопрос про удаление QProcess остаётся открыт. Так-то всё работает теперь, но утечка памяти образуется.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 12, 2012, 21:55
Вопрос про удаление QProcess остаётся открыт. Так-то всё работает теперь, но утечка памяти образуется.

А если делать deleteLater() вместо delete ?


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 12, 2012, 22:15
То работает, спасибо, не знал о таком слоте. Правда, количество процессов до 205-209 вскакивает, но далее не растёт. Теперь думаю как тормозить итерирование. QProcess в отдельном потоке запускается вроде?
Я пока пытаюсь родителем передавать в итератор указатель на поток, в котором он запускается, а в итераторе потом делать parent()->sleep(3), но не получается так. Почему-то родителем QObject получается у итератора. Это я где-то туплю, пока не понял просто где.

В pingthread:
Код:
IplistIterator *iplistIterator = new IplistIterator(tree, this);

в iplistiterator:
Код:
IplistIterator::IplistIterator(QTreeWidget *pTree, QObject *parent) : QObject(parent)
{
tree = pTree;
iterator = new QTreeWidgetItemIterator(tree, QTreeWidgetItemIterator::All);
}

void IplistIterator::finalize(bool result)
{
/* Заморочки с базой и.т.п. будут здесь */
if(result) (**iterator)->setIcon(0, QPixmap("./Resources/OK.jpg"));
else (**iterator)->setIcon(0, QPixmap("./Resources/notOK.jpg"));
++(*iterator);
if(!(**iterator)) { delete iterator; iterator = new QTreeWidgetItemIterator(tree, QTreeWidgetItemIterator::All); }
parent()->sleep(3);
emit nextPlease((**iterator)->text(0));
}

Сдаётся мне, что-то я о механизме наследования забыл что-то, пойду почитаю.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 12, 2012, 22:20
Я пока пытаюсь родителем передавать в итератор указатель на поток, в котором он запускается, а в итераторе потом делать parent()->sleep(3), но не получается так. Почему-то родителем QObject получается у итератора. Это я где-то туплю, пока не понял просто где.

parent() возвращает QObject*. Можешь использовать qobject_cast или dynamic_cast, чтобы привести его к нужному типу


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 12, 2012, 22:43
Код:
(qobject_cast<PingThread *>(parent()))->sleep(3);
Ругается компилятор, что sleep() - protected-член класса QThread, что так и есть, хех.
Что-то не вспоминается как можно из этого выбраться, разве что придётся слот создавать в pingthread, в нём делать sleep и уже им высылать сигнал запроса следующего элемента.


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 12, 2012, 22:50
Сделал слот отдельный для приёма, работает, но всё дико тормозит, включая итерфейс. Почему такое может быть?
Код:
#include <QThread>
#include <QTreeWidget>

PingThread::PingThread(QTreeWidget *pTree)
{
tree = pTree;
}

void PingThread::run()
{
PingString *pingString = new PingString;
IplistIterator *iplistIterator = new IplistIterator(tree);

connect(pingString, SIGNAL(pingResult(bool)), iplistIterator, SLOT(finalize(bool)));
connect(iplistIterator, SIGNAL(nextPlease(const QString &)), this, SLOT(checkRequest(const QString &)));
connect(this, SIGNAL(processNext(const QString &)), pingString, SLOT(pingAdress(const QString &)));

iplistIterator->start();
exec();
}

void PingThread::checkRequest(const QString &text)
{
sleep(3);
emit processNext(text);
}


Название: Re: Процесс внутри потока?
Отправлено: V1KT0P от Март 12, 2012, 23:27
Сделал слот отдельный для приёма, работает, но всё дико тормозит, включая итерфейс. Почему такое может быть?
После:
PingThread *pingThread = new PingThread;
Делал вот такое:
pingThread->moveToThread(pingThread);
Без этого сигналы работают не совсем так как от них ожидают.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 12, 2012, 23:33
После:
PingThread *pingThread = new PingThread;
Делал вот такое:
pingThread->moveToThread(pingThread);
Без этого сигналы работают не совсем так как от них ожидают.

Перемещать объект QThread в тред, которым он управляет, неправильно


Название: Re: Процесс внутри потока?
Отправлено: V1KT0P от Март 12, 2012, 23:40
После:
PingThread *pingThread = new PingThread;
Делал вот такое:
pingThread->moveToThread(pingThread);
Без этого сигналы работают не совсем так как от них ожидают.

Перемещать объект QThread в тред, которым он управляет, неправильно
А иначе обработка сигналов будет происходить не в самом потоке, а в том потоке где был создан экземпляр потока. Мало того что это может привести к ошибкам, так если экземпляр был создан в главном потоке то сигналы будут выполняться из главного потока тем самым тормозя графическую часть.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 12, 2012, 23:43
Значит нужно выносить рабочую часть из наследника QThread в отдельный класс и мувать его в обычный QThread

http://habrahabr.ru/blogs/qt_software/115830/
http://habrahabr.ru/blogs/qt_software/115835/
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/


Название: Re: Процесс внутри потока?
Отправлено: V1KT0P от Март 12, 2012, 23:53
Значит нужно выносить рабочую часть из наследника QThread в отдельный класс и мувать его в обычный QThread

http://habrahabr.ru/blogs/qt_software/115830/
http://habrahabr.ru/blogs/qt_software/115835/
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
Согласен, но как временное решение мувать самого в себя подойдет. Вот еще бы пример в справке показывал бы как надо правильно делать. Ибо я думаю многие об это спотыкаются.


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 13, 2012, 00:07
Значит нужно выносить рабочую часть из наследника QThread в отдельный класс и мувать его в обычный QThread

http://habrahabr.ru/blogs/qt_software/115830/
http://habrahabr.ru/blogs/qt_software/115835/
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
Согласен, но как временное решение мувать самого в себя подойдет. Вот еще бы пример в справке показывал бы как надо правильно делать. Ибо я думаю многие об это спотыкаются.

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


Название: Re: Процесс внутри потока?
Отправлено: mutineer от Март 13, 2012, 00:11
Сделал слот отдельный для приёма, работает, но всё дико тормозит, включая итерфейс. Почему такое может быть?

потому что sleep() вызвается в главном потоке ибо объект-наследник QThread живет в главном потоке и его слоты работают в нем (при автоконнекте). соответсвенно тормозишь ты главный поток

как вариант может помочь такое (если я правильно понял код):
Код:
connect(iplistIterator, SIGNAL(nextPlease(const QString &)), this, SLOT(checkRequest(const QString &)), Qt::DirectConnection);


Название: Re: Процесс внутри потока?
Отправлено: Igors от Март 13, 2012, 12:40
И, как я понимаю, если не удалять процесс, то будет утечка памяти, но почему всё же крашится, если удалять?
Не мешает посмотреть что пишет консоль. И вообще попечатать QThread::currentThreadId (где кто выполняется). Обычно выясняется много интересного

Опять прошу более опытных товарищей воздержаться от поучений и отправок в гугл/книгу,
Трудно воздержаться от назидательных фраз :)  Товарищи говорили - чем меньше логики в нитке - тем лучше. Но Вы опять втулили итератор в нитку. Результат

void IplistIterator::finalize(bool result)
{
   /* Заморочки с базой и.т.п. будут здесь */
   if(result) (**iterator)->setText(1, "OK!");
   else (**iterator)->setText(1, "FAIL :(");
А из какой нитки Вы дергаете UI? (можно только из главной)


Название: Re: Процесс внутри потока?
Отправлено: chron1c от Март 20, 2012, 09:16
С задачей разобрался, процесс перестал создавать/удалять, использую ->kill(), а потом ->start() для другого IP.
Решил вообще не использовать поток отдельный, а проверять айпи и переходить к следующему по timeOut у QTimer'а.
Спасибо всем за помощь :)

Возникла другая проблема теперь, но отдельную тему создавать не хочется для этого.
В классах своих создавал графические элементы динамически, а сейчас переделал и создал .ui для каждого класса.
По каким-то причинам не работает show() с объектом класса, для которого задан .ui.
Нужно внутри класса, из слота его, вызывать show(), пробовал и open() и this->show()/open(), даже извне пробовал show() вызывать - всё равно не отображается.
В чём может быть причина? В гугле ничего найти не удалось.

Сам объект(хотя так во всех объектах, переделанных с помощью добавления GUI-класса).
Код:
// ========== h
class ipSetWindow : public QDialog
{
Q_OBJECT

public:
ipSetWindow(bool gateway = false, QWidget *parent = 0);
~ipSetWindow();
public slots:
void modifyItem(QTreeWidgetItem *item, int column = 0);
private slots:
void sendIP();
void sendName();
void closeDialog();
private:
bool validate(QString &text); //Удаляет лишние нули и проверяет правильность айпишника (1-255.0-255.0-255.0-255), возвращает true, если всё ОК
QString *adress;
QTreeWidgetItem *pItem;
Ui::ipSetWindow ui;
};
//========== cpp
ipSetWindow::ipSetWindow(bool gateway, QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
pItem = 0;
adress = new QString;
ui.ipEdit->setInputMask("000.000.000.000;_");
ui.nameEdit->hide();
ui.okButton->hide();

connect(ui.nextButton, SIGNAL(clicked()), this, SLOT(sendIP()));
connect(ui.closeButton, SIGNAL(clicked()), this, SLOT(closeDialog()));
connect(ui.okButton,SIGNAL(clicked()), this, SLOT(sendName()));

setFixedSize(sizeHint());
}

ipSetWindow::~ipSetWindow()
{
delete adress;
}

void ipSetWindow::closeDialog()
{
ui.ipEdit->clear();
ui.nameEdit->clear();
pItem = 0;
close();
}

void ipSetWindow::modifyItem(QTreeWidgetItem *item, int column)
{
ui.ipEdit->setText(item->text(0));
ui.nameEdit->setText(item->text(1));
pItem = item;
show();
}