Название: sockets + threads, помогите :( Отправлено: yesrus от Март 12, 2009, 16:48 Здравствуйте!
Вообщем возникла проблема - подскажите пожалуйста как переделать пример blockingfortuneserver так, чтобы поток был не блокируемым (т.е. работал exec() евент луп в дочернем потоке). Идея такова - есть интерфейс (кнопочки..поля и т.д.), программа после загрузки настроек посылает сигнал коннект в тренд и оттуда (а не в основном потоке) создается коннект к серверу, далее в этом дочернем потоке связывается сигнал readyRead с слотом, при этом слот так же выполняется при вывове в дочернем потоке, после обработки данных слот должен посылать сигнал в основной поток (в котором крутится интерфейс) и на основе данных пришедших с сигналом в нем меняются данные (т.е. пишется в textedit лог ...меняется цвет кнопок или их состояний и т.д.). И основная проблема-как из главного потока (там где крутится интерфейс) послать сигнал(с данными) дочернему потоку(там где крутится сокет и установлен коннект с сервером). итого: 1) как после(!) загрузки опций(в основном потоке) или клика кнопки в основном потоке вызвать дочерний(при этом передать ему параметры\опции которые были считанны в основном потоке) в котором создать сокет и установить коннект к серверу 2) как посылать сигнал из дочернего потока в основной (при получении данных (т.е. при получении данных в дочернем потоке слот вызывает по readyRead слот, слот обрабатывает данные и посылает результат с помощью emit в основной поток где на основе этих данных что либо меняется (кнопки и т.д.))) 3) как из основного потока посылать сигнал на вызов слота в дочернем потоке (т.е. передать данные в слот в дочернем потоке (а слот после обработки передаст данные в сокет).(!!!) - это основная проблема т.к. тот же сокет я могу запустить в потоке, более того могу получить данные из него(в интернете полно примеров) т.к. могу связать его сигнал со слотом в основном потоке, НО я не могу вызвать слот дочернего потока (и сделать там write в сокет) из основного...пишет ерор...невозможно использовать сокет т.к. он в другом потоке (так и есть т.к. слот выполняется из основного потока т.к. его оттуда вызвали) так вот как вызвать слот таким образом, чтобы он отработал в дочернем потоке, а не в основном ? - этого нигде нет, потратил 2 дня на поиски и результата 0. Единственная просьба - пишите пожалуйста как и что нужно изменить в примере blockingfortuneclient (не просто ссылки на функции..а весь синтаксис т.к. я новичек и многих нюансов не знаю...) Заранее огромное спасибо за помощь! п.п.с. эта тему я думаю будет интересна многим т.к. видел очень много подобных вопросов которые был ик сожалению без ответа (везде все советуют как запустить сокет в потоке и читать оттуда данные, но нигде нет как записать данные в сокет который крутится в отдельном треде из основного потока(к котором интерфейс)(или из другого потока в котором ведется обработка данных т.е. в этмо случае уже 1 основной и 2 дочерних и данные нужно передавать между ними). п.п.п.с. мануал читал..много раз...по слоты и сигналы так же..но т.к. там нет примеров связи между тредами (только общие фразы и схемы) то ничего не понятно... Название: Re: sockets + threads, помогите :( Отправлено: EhTemka от Март 12, 2009, 21:52 ... И основная проблема-как из главного потока (там где крутится интерфейс) послать сигнал(с данными) дочернему потоку(там где крутится сокет и установлен коннект с сервером). А зачем сигнал? Можно воспользовался мютексом. Например myTread.h: Код
myTread.cpp Код
и где-нибудь в основном потоке Код
Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 12, 2009, 22:47 Хотелось бы без циклов, именно в луп эвенте все обрабатывать т.к. тот же readyRead не будет работать в цикле (т.к. это сигнал и без эвент лупа он не работает). =(
п.с. как я понимаю цикл это еще и большая нагрузка на процессор ? =( Название: Re: sockets + threads, помогите :( Отправлено: BRE от Март 12, 2009, 23:07 Код Создавай объект, связывай сигналы/слоты. Или в чем проблема? Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 12, 2009, 23:42 Я так и сделал первый раз...на что qt ругался...почти матом :D (единственное отличие от Вашего кода-я сокет создавал сразу в run()
Сейчас написал: Код: class tcpclient : public QThread Цитировать Thread::constructor: 0x28c Thread::run: 0xf68 QObject::moveToThread: Current thread (0x3e4ac8) is not the object's thread (0x22fd00). Cannot move to target thread (0x22fd00) QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x3ea188), parent's thread is QThread(0x3e4ac8), current thread is tcpclient(0x22fd00) QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x3ea188), parent's thread is QThread(0x3e4ac8), current thread is tcpclient(0x22fd00) ThreadMain: 0x28c QThread: Destroyed while thread is still running QObject: Cannot create children for a parent that is in a different thread. Собственно именно про это я и говорил в 1-м посте =( п.с. QThread::currentThreadId(); показывает, что и в каком треде отрабатывает. Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 00:09 Написал проектик. Исходнички прилогаются.
Компилируй. Запускай Qt Demo -> Fortune Server, указывай выделенный порт. Надеюсь поможет. Название: Re: sockets + threads, помогите :( Отправлено: BRE от Март 13, 2009, 00:18 Я запарился, да. :) m_socket->moveToThread( this ) переносим в конструктор.
После этого у меня работает, по крайней мере к fortuneserver подключается и ответ от него читает. Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 00:25 2 BRE Может легче m_socket = new QTcpSocket; в run-не делать, тогда moveToThread ненужен.
Или я чего-то недопонимаю? И еще вопрос по moveToThread. У меня есть непониманиее этой функции. Почему ей this передается, а не указатель на QThread? Run выполняется в другом потоке, отличном от того в котором выполняется конструктор класса. Как ей передать указатель на поток в Run? Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 01:13 2BRE - как я и говорил ругается при вызове слота sendData
Цитировать Thread::constructor: 0xdb4 Далее нажимаю кнопку Send и в дебаге вижуThread::run: 0xb3c GuiThread: 0xdb4 WorkerReadData: 0xdb4 Цитировать WorkerSendData: 0xdb4 QSocketNotifier: socket notifiers cannot be enabled from another thread 2igor_bogomolov - Спасибо за пример, но в нем нет как раз главной части - отправка сообщений из основного потока в сокет. п.с. и почему то программа во время запуска только на долю секунды показывает досовское окошко и мгновенно завершает работу, в дебаге Цитировать exited with code 0 Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 01:37 Подразумевалось общение с fortune server, оно все равно сообщения не обрботает.
Обновил архив - теперь с отправкой сообщения, бесполезной в данном случае, но все же Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 02:00 Вставил дебаг, результат ниже
Цитировать WorkerConstructor: 0xdd4 Main: 0xdd4 WorkerRun: 0xd90 QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x50a42a8), parent's thread is ThreadSocket(0x50a2300), current thread is QThread(0x3e4bc0) QObject: Cannot create children for a parent that is in a different thread. (Parent is QTcpSocket(0x50a42a8), parent's thread is ThreadSocket(0x50a2300), current thread is QThread(0x3e4bc0) WorkerConnectToHost: 0xdd4 WorkerConnected: 0xdd4 WorkerReadData: 0xdd4 QObject::connect: Cannot queue arguments of type 'QAbstractSocket::SocketError' (Make sure 'QAbstractSocket::SocketError' is registered using qRegisterMetaType().) WorkerSendData: 0xdd4 Как видно из лога сокет создается в основном треде (как результат подвешивает интерфейс на 5 сек при проверке Network operation timed out). =( Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 02:11 Попробуй добавить в конструктор Client
Код
Что пишет после добавления? Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 02:28 У меня
Цитировать warning: main TID: 0xe14 warning: run TID: 0xa90 Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 02:29 Изначально все, что в run() - выполняется в другом треде, это видно по WorkerRun: 0xd90, но как только идет попытка коннекта к серверу выскакивает QObject: Cannot create children for a parent that is in a different thread. потому, что сигнал на вызов слота приходит из мейнтреда, и как результат идет попытка выполнения слота в мейн треде -> ошибка т.к. сокет создан в другом треде(странно то, что в данном случае оно работает в основном...т.е сокет переносится в основной поток автоматически после ошибок...).
Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 02:36 а moveToThread добавили?
У меня после добавления все правильно заработало. Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 02:50 Спасибо! Все заработало.
Добавил аналог в свою программу...все так же отлично заработало... Все гениальное просто как говорится... Остался 1 вопрос-как сделать коннект из потока в основной поток...т.е. к примеру я делаю в конструкторе GUI (worker это объект в котором выполняется сокет т.е. другой поток) Цитировать connect(this, SIGNAL(sendData( const QString & )), worker, SLOT(sendData(const QString &))); Как сделать то же самое(так же соеденить сигнал sendData основного потока с слотом sendData дочернего потока) из потока ? т.е. в конструкторе объекта worker ?Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 03:10 Не совсем понимаю зачем?
Чем неустраивает коннект в GUI, Вы же все равно worker создаете в нем? Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 11:46 Ну к примеру будет 2 или больше нитей..и коннект между ними нужен.
Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 11:53 Так в чем проблема?
Код
Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 12:42 А к основному потоку ? Какой у него идентификатор.
Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 12:50 this
Или я вопроса не понял? ??? Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 14:03 Сделать коннект из к примеру run() функции дочернего потока, если написать this то будет соединение с этим потоком..а нужно с основным.
Название: Re: sockets + threads, помогите :( Отправлено: igor_bogomolov от Март 13, 2009, 15:20 Если уж так сильно хочется, можно сделать так:
Код: Client *pClient; Код: #include "Client.h" Только на мой взгляд так делать неправельно. Еще раз повторюсь. Вы все равно создаете экземпляры класса ThreadSocket в конструкторе, в данном примере, класса Client. Вот и создавайте все коннекты между этими классами там же. Т.е Код: Client::Client(QWidget *parent) : QMainWindow(parent) { Название: Re: sockets + threads, помогите :( Отправлено: yesrus от Март 13, 2009, 15:43 Понятно, спасибо огромное за помощь!
|