Russian Qt Forum

Программирование => Общий => Тема начата: Buran от Июнь 10, 2010, 13:01



Название: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 13:01
Приветствую всех.
Есть вопрос по QThread.

Создаю примерно так:

Код:
MyThread : public QThread
{

MyThread()
{
QTcpSocket socket = new QTcpSocket();
......
......
......
}


void socketWrite(QByteArray str)
{
socket->write(str);
}

}
Во время выполнения socket->write(str) выводит ошибку, что не может сделать, т.к. родительский и дочерний потоки - разные.
И действительно, this - показывает указывает на один thread, а socket->thread() - на другой.

Т.е. new QtcpSocket() создается в отдельном потоке. Наверное так и должно быть?

Вопрос: Как мне создать socket в моем потоке? Чтобы this и socket->thread() возвращали указатель на один и тот же thread?
Или может мне socket'у указать socket->MoveToThread(this) (это только идея).



UPD:
Прочитал, что можно вызвать в функции run(). Но теперь не приходит SIGNAL(readyRead()). Почему? Ведь очередь сообщений теперь в моем новом потоке, а не в основном.
Подскажите, пжл, чего я не догоняю?


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 10, 2010, 13:20
UPD:
Прочитал, что можно вызвать в функции run(). Но теперь не приходит SIGNAL(readyRead()). Почему? Ведь очередь сообщений теперь в моем новом потоке, а не в основном.
Подскажите, пжл, чего я не догоняю?
потому что поток умирает вместе с объектами которые были в нём созданы. Поставь в run()'e exec(), и глуши его когда надо будет


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 14:04
UPD:
Прочитал, что можно вызвать в функции run(). Но теперь не приходит SIGNAL(readyRead()). Почему? Ведь очередь сообщений теперь в моем новом потоке, а не в основном.
Подскажите, пжл, чего я не догоняю?
потому что поток умирает вместе с объектами которые были в нём созданы. Поставь в run()'e exec(), и глуши его когда надо будет


Брррр....
У меня поток не умирает. Он работает, это легко подтверждается выполняемым в нем кодом. И emit слота же работает!

Не срабатывает сигнал:
Код:
class MyThread : public QThread
{

MyThread()
{
}


void run()
{
QTcpSocket* socket = new QTcpSocket();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
}

}

Насколько я понимаю, это может быть только если:
а) умер socket. Но, socket есть, можно запросить на него указатель.;
б) что-то с очередью сообщений;

UPD:
Кажись exec() как раз очередь сообщений и запускает. Сейчас проверю....)


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 14:31
потому что поток умирает вместе с объектами которые были в нём созданы. Поставь в run()'e exec(), и глуши его когда надо будет
По умолчанию в QThread::run как раз один exec() и запускается.


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 14:32
Код
C++ (Qt)
class MyThread : public QThread
{
 
MyThread()
{
}
 
 
void run()
{
QTcpSocket* socket = new QTcpSocket();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
       exec();
}
 
}


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 14:52
Код
C++ (Qt)
 
void run()
{
QTcpSocket* socket = new QTcpSocket();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
       exec();
}
 
}


Ура! Очередь сообщений заработала. Но вот выполнение потока остановилось.(

Если быть точным, то кроме связывания сигнала и слота в run() еще есть while(). Внутри которого идет постоянное выполнение кода.

И вот при exec() оно (выполнение кода в while()) останавливается.

Пока не очень понимаю почему.


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 14:56
Пока не очень понимаю почему.
Потому, что в exec() запускается бесконечный цикл обработки событий.
Ты должен определиться, что тебе нужно. Если нужна возможность получения сигналов, то нужен exec (точнее обработка событий) и тогда с выполнением другого кода в потоке нужно думать.
Расскажи, что ты хочешь обрабатывать в цикле while()?


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 10, 2010, 15:02
Совершенно не понял фразы
По умолчанию в QThread::run как раз один exec() и запускается.

А это
Код
C++ (Qt)
class MyThread : public QThread
{
 
MyThread()
{
}
 
 
void run()
{
QTcpSocket* socket = new QTcpSocket();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
       exec();
}
 
}
вообще-то и имел ввиду


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 15:04
Расскажи, что ты хочешь обрабатывать в цикле while()?

По событию socket, SIGNAL(readyRead()) происходит обработка сокета.
А в while постоянно мониторится RS-232. Т.к. в QextSerialPort нифига не работает сигнал readyRead() я его (RS) просматриваю вручную.

Данные в потоке кидаются между ними.

В принципе, в никсах, я могу это обойти привязавшись к файлу /dev/ttyS# и смотреть его notify(). Но тогда в винда (в случае чего) мне не светит.


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 15:09
По событию socket, SIGNAL(readyRead()) происходит обработка сокета.
А в while постоянно мониторится RS-232. Т.к. в QextSerialPort нифига не работает сигнал readyRead() я его (RS) просматриваю вручную.
Ты в одном потоке и RS-232 мониторишь и из сетки данные получаешь?


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 15:10
По событию socket, SIGNAL(readyRead()) происходит обработка сокета.
А в while постоянно мониторится RS-232. Т.к. в QextSerialPort нифига не работает сигнал readyRead() я его (RS) просматриваю вручную.
Ты в одном потоке и RS-232 мониторишь и из сетки данные получаешь?


Угу.


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 10, 2010, 15:11
BRE, ну так что ты хотел сказать насчёт exec()?


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 15:15
BRE, ну так что ты хотел сказать насчёт exec()?
То, что если run() не переопределять, то там как раз exec() и запускается. А вот если переопределять, то его нужно вызывать явно или вызывать QThread::run():
Код
C++ (Qt)
void MyThread::run()
{
       QTcpSocket* socket = new QTcpSocket();
       QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
QThread::run(); // или exec()
}
 


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 15:20
Угу.
Можно запустить таймер в этом потоке и через заданный интервал проверять состояние порта или разнести получение данных из сети и проверку порта по разным потокам.


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 10, 2010, 15:25
[То, что если run() не переопределять, то там как раз exec() и запускается. А вот если переопределять, то его нужно вызывать явно или вызывать QThread::run():
Код
C++ (Qt)
void MyThread::run()
{
       QTcpSocket* socket = new QTcpSocket();
       QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(SockerRead()));
QThread::run(); // или exec()
}
 
ну естесственно его надо было переопределить, как же без этого-то! Какой смысл в потоке, если сам run() будет пустым))


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 15:35
ну естесственно его надо было переопределить, как же без этого-то! Какой смысл в потоке, если сам run() будет пустым))
Объекты можно создать и извне и перетащить в пространство потока. Так что иногда можно и не переопределять.


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 10, 2010, 15:44
Можно конечно, но только сейчас заметил, что ТС намекал именно на этот способ, разобрались.


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 15:59
Тогда вопрос по moveToThread().

Код:
class MyThread : public QThread

MyThread()
{
QTcpSocket socket = new QTcpSocket();
}

void run()
{
socket->write(QByteArray);
}

Когда я обращаюсь из run к socket получаю ошибку невозможности вызова write потому что потоки разные.

а) Праль-но ли я понимаю, что new QTcpSocket() создается в главном потоке. А то, что выполняется в run - это уже мною созданный поток, который совсем-совсем другой?

б) Пробовал использовать socket->moveToThread(this) в конструкторе - не помогает (потоки по прежнему разные), может прямо в run'е прописать этот мув?


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 16:10
а) Праль-но ли я понимаю, что new QTcpSocket() создается в главном потоке. А то, что выполняется в run - это уже мною созданный поток, который совсем-совсем другой?
Правильно.

б) Пробовал использовать socket->moveToThread(this) в конструкторе - не помогает (потоки по прежнему разные)?
Странно. А в консоле при выполнении Qt что пишет?
И код более подробно приведи.


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 16:58

И код более подробно приведи.

Код:
class MyThread : public QThread
{
MyThread()
{
socket = new QTcpSocket();

qDebug() << "OLD socket thread: " << this->thread();  // *1
socket->setParent(0);
socket->moveToThread(this);
qDebug() << "NEW socket thread: " << this->thread();  // *2
}

void run()
{
socket->write(QByteArray);
}

void socketWrite(QByteArray)
{
qDebug() << "WRITE socket thread: " << this->thread();  // *3
socket->write(QByteArray);
}
}

Вывод по точкам:
*1: QThread(0x8d2cd60)
*2: MyThread(0x8e82bc8)
*3: QThread(0x8d2cd60)


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 17:04
socket->setParent(0) можно не писать, ты и так не указал parent объекту socket, т.е. его parent == 0.

Кто вызывает метод socketWrite?

 ::) Два вывода qDebug в конструкторе точно это выводят? Или там все таки socket->thread(), а не this->thread().

И это... объект потока MyThread находится в контексте того потока, в котором он создавался (в главном потоке), поэтому this->thread() должен возвращать всегда одинаковый результат. Если хочешь перенести объект потока в контекст этого потока - ему тоже нужно сказать moveToThread( this ).
Для определения в каком контексте выполняется код, лучше использовать статический метод:
Qt::HANDLE QThread::currentThreadId ()   [static]


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 19:31
socket->setParent(0) можно не писать, ты и так не указал parent объекту socket, т.е. его parent == 0.

Кто вызывает метод socketWrite?

вызывает его читалка когда в RS приходят данные.



 ::) Два вывода qDebug в конструкторе точно это выводят? Или там все таки socket->thread(), а не this->thread().

Ооооо... Ну конечно опечатался, когда постил. Там конечно же socket->thread()  :)


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 19:37
вызывает его читалка когда в RS приходят данные.
А где код, который это реализует. Это слот? Как и где к нему конектятся?


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 10, 2010, 20:17
вызывает его читалка когда в RS приходят данные.
А где код, который это реализует. Это слот? Как и где к нему конектятся?


Нет, я уже описывал, что в используемой RS библиотеке readyRead не работает, поэтому сигналы-слоты использовать неудобно. Я в run'е проверяю пришедшие данные в RS  и если пришли - вызов this->socketWrite(пришедший из RS текст).

Т.е. судя по всему я пытаюсь вызвать метод объекта основного потока(MyThread) из дочернего(который выполняется в run).

Так?



Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 10, 2010, 20:28
Т.е. судя по всему я пытаюсь вызвать метод объекта основного потока(MyThread) из дочернего(который выполняется в run).
Так?
Все что вызывается из run - выполняется в контексте самого потока.
Вопросы возникают при использовании сигнально-слотовой системы.


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 11, 2010, 00:55
Т.е. судя по всему я пытаюсь вызвать метод объекта основного потока(MyThread) из дочернего(который выполняется в run).
Так?
Все что вызывается из run - выполняется в контексте самого потока.
Вопросы возникают при использовании сигнально-слотовой системы.

У меня почему-то не так.

Смотри что получается.

Если делаю moveToThread, то socket->thread() выдает указатель на мой новый, только что созданный поток.
И когда я из run (вот важно!) вызываю socket->socketWrite() и вывожу там указатель (см. код выше), то получаю указатель на основной поток (несмотря на то, что вызвал я его из run). И тут есс-но слоты у меня не арбайтен (потоки-то разные).

А если НЕ делаю, то указатель на поток socket->thread() и тот указатель, что выводится внутри socketWrite() одинаковые и тут связка сигнал-слот работает на отлично. Плохо только, что вызов из run (указатель на поток уже новый) не работает.

Тут родилась идея. Может код работы с RS положить в метод и просто вызывать его из run.
Код:
	void run()
{
this->checkRS()
}

void checkRS()
{
.....
.....
socket->socketWrite()
}

void socketWrite()
{
socket->write()
}

Но ведь в этом случае теряется смысл отдельных потоков, поскольку обработка вызываемых методов будет происходить в основном потоке?


Название: Re: QTcpSocket внутри Qthread
Отправлено: serg_hd от Июнь 11, 2010, 02:56
И когда я из run (вот важно!) вызываю socket->socketWrite() и вывожу там указатель (см. код выше), то получаю указатель на основной поток (несмотря на то, что вызвал я его из run). И тут есс-но слоты у меня не арбайтен (потоки-то разные).

В код особо не вникал, но
Код
C++ (Qt)
socket = new QTcpSocket();
 
ты создал в главном.
Я вобщем-то всегда считал (где-то на этом же форуме даже встретил тему с похожей ситуацией когда-то), что если ты вызываешь методы какого-либо объекта, не важно в каком потоке, то они, методы эти, будут выполнятся в контексте того потока, в котором был создан объект.
А что касается соединения главного с второстепенным посредством сигнала/слота, то лучше воспользоваться типом (соединения) DirectConnection - тогда этот слот выполнится в контексте второстепенного, имею ввиду если сигнал будет испускать второстепенный, - вдруг пригодится...


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 11, 2010, 07:08
У меня почему-то не так.

Смотри что получается.

Если делаю moveToThread, то socket->thread() выдает указатель на мой новый, только что созданный поток.
И когда я из run (вот важно!) вызываю socket->socketWrite() и вывожу там указатель (см. код выше), то получаю указатель на основной поток (несмотря на то, что вызвал я его из run). И тут есс-но слоты у меня не арбайтен (потоки-то разные).
Это потому что ты не так проверяешь. Чуть выше я писал:
Цитировать
Для определения в каком контексте выполняется код, лучше использовать статический метод:
Qt::HANDLE QThread::currentThreadId ()   [static]
Метод QObject::thread() возвращает указатель на поток, которому этот объект принадлежит. Используется это значение в методе connect для определения какой тип подключения выбрать для соединения объектов.

Так же я писал, что сам объект класса MyThread принадлежит создающему его поток (главному например). Поэтому, если ты в этом классе описал слоты и хочешь что-бы они выполнялись в контексте нового потока MyThread, то этот объект нужно переместить в контекст этого потока.
Код
C++ (Qt)
MyThread::MyThread()
{
moveToThread( this ); // Перемещаем сам объект класса MyThread в контекст его потока
...
}
 


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 11, 2010, 15:25
Для определения в каком контексте выполняется код, лучше использовать статический метод:
Qt::HANDLE QThread::currentThreadId ()   [static]

Пасиб, пропустил. Действительно выводит совсем другие значения.)


Код
C++ (Qt)
MyThread::MyThread()
{
moveToThread( this );
...
}
 


А когда он переместится в ново-созданный поток, есть ощущение, что мне снова надо будет запускать очередь сообщений exec'ом.
И в run'е я не смогу выполнять проверку RS.

Так?


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 11, 2010, 15:39
А когда он переместится в ново-созданный поток, есть ощущение, что мне снова надо будет запускать очередь сообщений exec'ом.
Ну на самом деле никуда ничего не переноситься. Все потоки одного процесса выполняются в одном адресном пространстве. Эта конструкция просто отмечает к какому потоку будет относиться объект, для выполнения корректного коннекта (я чуть выше про это писал).
Если нужно получать сигналы в потоке, то без exec не обойтись. Его придется запускать.

И в run'е я не смогу выполнять проверку RS.
Так?
Попробуй по таймеру проверять состояние RS в этом же потоке. Запусти таймер и в обработчике сигнала timeout проверяй его состояние.


Название: Re: QTcpSocket внутри Qthread
Отправлено: ieroglif от Июнь 11, 2010, 18:21
не понимаю - зачем держать оба обработчика (на сеть и на железку) в одном потоке?
имхо, это не логично.
что если разнести их по разным потокам? в потоке на железку будет спокойно себе крутиться цикл проверки железки и когда надо сигналить байтарреем в слот потока работы с сетью.. не катит?


Название: Re: QTcpSocket внутри Qthread
Отправлено: BRE от Июнь 11, 2010, 18:23
не понимаю - зачем держать оба обработчика (на сеть и на железку) в одном потоке?
имхо, это не логично.
что если разнести их по разным потокам? в потоке на железку будет спокойно себе крутиться цикл проверки железки и когда надо сигналить байтарреем в слот потока работы с сетью.. не катит?
Ответ, на аналогичное предложение (несколькими постами выше), тоже не получил.  ::)


Название: Re: QTcpSocket внутри Qthread
Отправлено: Buran от Июнь 12, 2010, 18:40
Ответ, на аналогичное предложение (несколькими постами выше), тоже не получил.  ::)

Предложение логичное и даже очень. Правда таких кроссов (сеть-КОМ) может быть и десяток и тогда таких потоков будет как минимум n*2+1

Хм... Вы предлагаете мне сдаться...?! Это не путь настоящих Джедаев. Где ж я еще такие грабли найду...это же чистое знание.))


Название: Re: QTcpSocket внутри Qthread
Отправлено: ieroglif от Июнь 12, 2010, 19:54
Ответ, на аналогичное предложение (несколькими постами выше), тоже не получил.  ::)

Предложение логичное и даже очень. Правда таких кроссов (сеть-КОМ) может быть и десяток и тогда таких потоков будет как минимум n*2+1

Хм... Вы предлагаете мне сдаться...?! Это не путь настоящих Джедаев. Где ж я еще такие грабли найду...это же чистое знание.))
2. не надо сдаваться. граблей таких можно найти много где =) (например займись геймдевом)
1. зачем такие извращения? один поток опрашивает 10 железок по очереди (или 2 потока по 5 железок) - я уверен что будет нормально работать, так же как и 1-2 потока на 10 сетевых соединений


Название: Re: QTcpSocket внутри Qthread
Отправлено: pethead от Ноябрь 05, 2010, 20:34
я сделал так.
создал класс потока с сокетом внутри, и сразу его засунул movetothread самого в себя. прописал в нем сигнал\слоты на события сокета: прием, таймаут. в нем запущен exec.
создал еще один поток, и его засунул самого в себя,в run теперь цикл while, в котором я управляю сокетным потоком через сигналы.
оба потока принадлежат одному классу (не от QObject, поэтому он сам не может участвовать в сигнал\слотах).