Название: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 04, 2009, 08:38 Доброго времени суток!
помогите разобраться со следующей задачей: существует основной поток, выполняющий обработку данных и множество входящих подключений по TCP. соответственно, для каждого нового подключения хочется запускать отдельный поток, который бы его обслуживал (т.е. передвал в него данные и считывал ответ клиента), при этом выполняя обмен данными с основным потоком (который обрабатывает эти данные). почитал, посмотрел примеры реализации подобных серверных приложений и решил сделать используя QThread + QTcpSocket. создав основной класс от QTcpServer , и порождая новые нити при каждом новом подключении. в итоге получил нечто вида: Код: void chat_deamon::incomingConnection(int socketDescriptor) Код: void chat_trhead::run() возводя при этом флаги и обрабатывая их в цикле while(1) в run() Код: void chat_trhead::upd_users(QString nul) и все это работает, причем вроде даже хорошо, но: 1) передавать данные через сигналы не очень удобно, можно ли для этого передавать указатель на общие данные и писать/читать уже оттуда используя QRWlock(), не сильно ли это скажется на надежности и скорости приложения? 2) если к примеру требуется передать данные через сигнал КОНКРЕТНОМУ приемнику, как это сделать? ведь connect в данном случае привязывает слоты КАЖДОГО потока к одному СИГНАЛУ сервера, и следовательно, при его использовании данные рассылаются всем нитям, а не конкретной, можно ли как то ее идентифицировать и общаться с ней? 3) можно ли создать поток обработки QTcpSocket в отдельной нити так, что бы он обрабатывался не через while(1)... а через сигналы readyRead() и т.д. а то после окончания run() достучаться до потока уже немогу ( ... подскажите как лучше сделать? Название: Re: QThread + QTcpSocket + основной поток Отправлено: kuzulis от Августа 04, 2009, 10:49 Цитировать 3) можно ли создать поток обработки QTcpSocket в отдельной нити так, что бы он обрабатывался не через while(1)... а через сигналы readyRead() и т.д. а то после окончания run() достучаться до потока уже немогу ( мож сделать так:Код: void chat_trhead::run() Название: Re: QThread + QTcpSocket + основной поток Отправлено: Winstrol от Августа 04, 2009, 14:07 3) можно ли создать поток обработки QTcpSocket в отдельной нити так, что бы он обрабатывался не через while(1)... а через сигналы readyRead() и т.д. а то после окончания run() достучаться до потока уже немогу ( ... Для работы через сигналы readyRead() надо либо не переопределять метод run, либо, совершив некоторые предварительные действия в переопределенном run, вызвать цикл обработки событий (в том числе от сокетов) - метод exec(). Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 05, 2009, 01:45 Спасибо буду тестить :)
а что можете посоветовать по поводу того как обратиться к конкретному потоку (через сигнал) ? Название: Re: QThread + QTcpSocket + основной поток Отправлено: alexman от Августа 05, 2009, 07:52 1) Можно использовать глобальный буфер, но его внутренние данные которые изменяются потоками необходимо закрыть мьютексом или семафором в зависимости от ситуации.
2) Можно реализовать глобальный proxy-класс, который будет отфильтровывать сообщения и посылать сигналы требуемым потокам. 3) while(1) плохо, так как процессор грузиться. Лучше использовать while(1), но внутри засыпать на QWaitCondition, а далее постоянно будить поток по сигналу readyRead. Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 05, 2009, 08:01 1) Можно использовать глобальный буфер, но его внутренние данные которые изменяются потоками необходимо закрыть мьютексом или семафором в зависимости от ситуации. по сути сделать общие ресурсы и управлять через них?..2) Можно реализовать глобальный proxy-класс, который будет отфильтровывать сообщения и посылать сигналы требуемым потокам. а как такое сделать??3) while(1) плохо, так как процессор грузиться. Лучше использовать while(1), но внутри засыпать на QWaitCondition, а далее постоянно будить поток по сигналу readyRead. я думал так сделать, но ,во-первых, у меня таких Condition может быть несколько (поток просыпается не только по получению readRead() но и других сигналов), можно ли это увязать в пределах QWaitCondition ??, а, во-вторых, смущает строчка из assistenta :Цитировать void QWaitCondition::wakeOne () не будет ли проблем разбудить "конкретный" поток таким путем??Wakes one thread waiting on the wait condition. The thread that is woken up depends on the operating system's scheduling policies, and cannot be controlled or predicted. If you want to wake up a specific thread, the solution is typically to use different wait conditions and have different threads wait on different conditions. Название: Re: QThread + QTcpSocket + основной поток Отправлено: ритт от Августа 05, 2009, 08:09 1. жесть
2. жесть 3. плохо. либо waitForConnected, либо петлю на connectNotify запоминай кто коннектился к сигналу (на disconnectNotify убирай запись из списка), когда узнал кому "отправлять сигнал" (видимо, данная задача это подразумевает), делай QMetaObject::invokeMethod советую использовать петлю. зы. и далеко не всегда поток на сокет - хорошее решение Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 05, 2009, 08:15 1. жесть ага )2. жесть 3. плохо. либо waitForConnected, либо петлю петлю - в смысле while(1) ?на connectNotify запоминай кто коннектился к сигналу (на disconnectNotify убирай запись из списка), когда узнал кому "отправлять сигнал" (видимо, данная задача это подразумевает), делай QMetaObject::invokeMethod советую использовать петлю. зы. и далеко не всегда поток на сокет - хорошее решение а как еще можно обеспечить параллельную работу основного потока (вычисления) с передачей в него и из него данных в сокеты ?Название: Re: QThread + QTcpSocket + основной поток Отправлено: BRE от Августа 05, 2009, 08:28 Рекомендую прочесть статейку:
http://www.opennet.ru/base/dev/server_way.txt.html Название: Re: QThread + QTcpSocket + основной поток Отправлено: alexman от Августа 05, 2009, 08:40 1. Не жесть, а часто используемое решение.
2. На счёт этого согласен) Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 05, 2009, 08:43 1. Не жесть, а часто используемое решение. ага с этого начинал )2. На счёт этого согласен) мне в принципе интересно как ето сделать )))Название: Re: QThread + QTcpSocket + основной поток Отправлено: ритт от Августа 05, 2009, 10:13 Код: class MyThread : public QThread Название: Re: QThread + QTcpSocket + основной поток Отправлено: Fastman от Августа 05, 2009, 23:10 У меня например сделан отдельный класс для обработки сообщений.
Все как и выше практически: Сам сервак который слушает клиентов: Код: void CTcpCast::StartServer(qint32 nPort) Поточный класс: Код:
А вот CConnection: Код: CConnection::CConnection(QObject *parent) Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 18, 2009, 06:41 возник новый вопрос...
а как правильно организовать работу с общей памятью для множества процессов? создать отдельный класс для хранения данных и передать всем на него указатель? при каждом обращении к данному классу необходимо делать QMutex ? подскажите пожалуйста, а то что то завис ??? Название: Re: QThread + QTcpSocket + основной поток Отправлено: denka от Августа 18, 2009, 08:40 Глянь вот это http://doc.trolltech.com/4.4/qsharedmemory.html (http://doc.trolltech.com/4.4/qsharedmemory.html)
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 18, 2009, 09:41 Хм, подскажите, где я затупил?
после строчки (QThread)->run() где в самом run() последней строкой идет exec() выполнение кода никогда не произойдет... или вернее произойдет наверное когда "поток" завершиться... почему после запуска обработчика exec() управление не возвращается?... осознал свой косяк, запускать поток надо через start() ;D , но после этого вылезла проблема с QObject и детьми из другого потока ))) где то тут про это было, буду искать :) Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 18, 2009, 10:14 Все спасибо соседнему топику про QTcpServer в QThread
оставлю тут как заметку для тех кто натыкается на эти грабли: при создании своего потока необходимо сделать следующее: 1) переопределить QThread, конструктор и метод run(); 2) для орагнизации полноценного цикла обработки в конце метода run(), вызвать exec(); 3) переместить обработку потока в сам поток ;D , для этого после создания потока вызвать (мой класс потока)->moveToThread(мой класс потока); 4) после чего запустить обработку всего этого командой ->start() если я где то не прав, ткните где :) Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 18, 2009, 10:29 я сделал setSocketDesctiptor после того, как привязал сигнал readyRead к слоту в потоке и обрабатываю сигнал processData, чтобы обработать данные
Код: class MLNetThread : public QThread{ Код: MLNetThread::MLNetThread(int socketDesc, QObject* pParent): Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 18, 2009, 10:32 Хм, подскажите, где я затупил? в самом классе QThread храни только указатели, а создавай обьекты в run и помни, что QThread сам по себе находится в другом потоке, так что не вызывай его функции напрямую, обрабатывай сигналы и все)после строчки (QThread)->run() где в самом run() последней строкой идет exec() выполнение кода никогда не произойдет... или вернее произойдет наверное когда "поток" завершиться... почему после запуска обработчика exec() управление не возвращается?... осознал свой косяк, запускать поток надо через start() ;D , но после этого вылезла проблема с QObject и детьми из другого потока ))) где то тут про это было, буду искать :) Название: Re: QThread + QTcpSocket + основной поток Отправлено: BRE от Августа 18, 2009, 10:47 в самом классе QThread храни только указатели, а создавай обьекты в run и помни, что QThread сам по себе находится в другом потоке, так что не вызывай его функции напрямую, обрабатывай сигналы и все) Можно и локальными объектами пользоваться:Код
Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 18, 2009, 11:08 вообще, я так понимаю, если хочешь, чтобы вся работа потока выполнялась непосредственно в потоке, то нет смысла определять какие либо методы, кроме run.. А уже непосредственно в run создаешь классы, к которым и от которых подключаешь сигналы из основного потока.. А сам QThread сделать минимальным)
Название: Re: QThread + QTcpSocket + основной поток Отправлено: pastor от Августа 18, 2009, 11:09 ...и помни, что QThread сам по себе находится в другом потоке, так что не вызывай его функции напрямую... Да? А где про такое пишут, что весь QThread (наследник QThread, я правильно понял?) находится в другом потоке? Всю жизнь только run был "началом" другого потока, а вот принадлежность методов QThread (наследника QThread) к другому или главному потоку зависела от способа вызова (вызов из главного или второстепенного потока). Название: Re: QThread + QTcpSocket + основной поток Отправлено: pastor от Августа 18, 2009, 11:11 вообще, я так понимаю, если хочешь, чтобы вся работа потока выполнялась непосредственно в потоке, то нет смысла определять какие либо методы, кроме run. Никакой проблемы в создании доп методов нет. Хочешь чтобы эти методы выполнялись в доп. потоке - вызывай их из него (из run) Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 18, 2009, 11:13 ...и помни, что QThread сам по себе находится в другом потоке, так что не вызывай его функции напрямую... Да? А где про такое пишут, что весь QThread (наследник QThread, я правильно понял?) находится в другом потоке? Всю жизнь только run был "началом" другого потока, а вот принадлежность методов QThread (наследника QThread) к другому или главному потоку зависела от способа вызова (вызов из главного или второстепенного потока). Вызывая методы класса находящегося в конкретном потоке мы добьемся их выполнения исключительно в том же самом потоке, что и класс(кроме статических методов) Название: Re: QThread + QTcpSocket + основной поток Отправлено: pastor от Августа 18, 2009, 11:15 а обьекты созданные в его методе run() находятся в потоке QThread Верно :) Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 18, 2009, 11:27 вообще, я так понимаю, если хочешь, чтобы вся работа потока выполнялась непосредственно в потоке, то нет смысла определять какие либо методы, кроме run. Никакой проблемы в создании доп методов нет. Хочешь чтобы эти методы выполнялись в доп. потоке - вызывай их из него (из run) ...работает) но всеравно изменяешь данные как правило если пришел сигнал что их получил) а если сигнал подключаешь непосредственно в QThread, то и обрабатываться данные будут в главном потоке.. Для того, чтобы работа происходила во внутреннем потоке необходимо подключать сигналы к обьектам потока... А то вдруг ты обрабатываешь данные во внешнем в то время как во внутреннем они изменились, лочить внутренний поток придется.. Название: Re: QThread + QTcpSocket + основной поток Отправлено: pastor от Августа 18, 2009, 13:37 Для этого нужно ознакомиться с методами синхронизации потоков и проблем никогда небудет. Сингалы\слоты, эвенты это, можно так сказать, способы "общения" между потоками. Но мне никто не запрещает "общаться" между потоками напрямую (естественно, синхронизировав при этом работу)
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 19, 2009, 01:35 а еще вопрос несколько не в тему, но около того, подскажите как правильно работает QMutex (ну и вообще мутексы)
как я понял (а возможно понял я не правильно), он ограничивает доступ к следующим за ним командам/данным, до тех пор пока не будет вызван unlock(). Если это так, тогда зачем создавать и использовать более одного экземпляра данного класса в приложении? когда может возникунть такая потребность?... и к примеру задачка, есть у меня класс выполняющий обработку и хранение данных, сам экземпляр класса запущен в основном потоке (по крайней мере я так думаю, т.к. создан он в нем), указатели на него переданы в дочерние потоки, которые выполняют определенные взаимодействия с другими системами через сокеты (распределенные вычисления), и из этих потоков переодически необходимо вызывать этот класс для получения или передачи в него данных... вопрос, правильно ли будет использовать QMutex в самом классе (к примеру при вызове метода записи данных, блокировать эти саммые данные) и что произойдет в таком случае, если 2 потока вызовут этот метод "одновременно"? Название: Re: QThread + QTcpSocket + основной поток Отправлено: boobsik от Августа 19, 2009, 01:48 и что произойдет в таком случае, если 2 потока вызовут этот метод "одновременно"? When you call lock() in a thread, other threads that try to call lock() in the SAME PLACE will block until the thread that got the lock calls unlock()Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 19, 2009, 01:59 и что произойдет в таком случае, если 2 потока вызовут этот метод "одновременно"? When you call lock() in a thread, other threads that try to call lock() in the SAME PLACE will block until the thread that got the lock calls unlock()Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 21, 2009, 04:12 Подскажите кто знает, почему может при разрыве соединения, QTcpSocket не эмитит disconnected() ? и приходиться самому переодически проверять socket->state().. ? есть ли другое решение?
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Rcus от Августа 21, 2009, 05:14 Значит disconnected не излучается а state() выдает QAbstractSocket::UnconnectedState? Интересно... У меня почему-то все нормально работает. Но это зависит от того что вы понимаете под разрывом соединения.
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 21, 2009, 06:27 когда как, иногда бывает и излучается, но 1 раз из 10 дисконектов...
а под дисконнектом я подразумеваю, уничтожение на противоположном конце QTcpSocket ... (пользователь прибил процесс) Название: Re: QThread + QTcpSocket + основной поток Отправлено: Rcus от Августа 21, 2009, 07:17 Прибил всмысле kill -9? Ну так конечно, сокет на другой стороне тогда не получит сообщение об отключении. Смотрите в сторону keep-alive.
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Vexator от Августа 21, 2009, 07:47 Странно, а почему тогда состояние корректно меняется?
Название: Re: QThread + QTcpSocket + основной поток Отправлено: Rcus от Августа 21, 2009, 07:55 /* shrugs */ А что насчет сигналов stateChanged и error?
|