Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [QT4] Многопоточный сервер 
V
    Опции темы
SwordOfDeath
  Дата 19.7.2009, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Всем привет

Столкнулся с проблемой... В примере Threaded Fortune Server не описан процесс обмена данными... они только посылаются и сразу же закрывается поток (что очень странно, смысла в многопоточности для такой проги ноль...)

Я пытался переделать и совместить Threaded Fortune Server c Loopback... И уже разобрался что в потоке нужно запустить event loop через exec() но натолкнулся на проблему.

Как я понял если для QTcpSocket указать socketDescriptor то он начинает отрабатывать сообщения этого сокета... Так вот если я в потоке пытаюсь поставить setSocketDescriptor(socketDescriptor) то ругается в окно вывода проги:
Код

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x8c71a58), parent's thread is QThread(0x3e5030), current thread is MainThread(0x8c71a48)

А если переношу QTcpSocket в новосозданный поток (thread->tcpServerConnection.moveToThread(thread)), причем ругается в exec():
Код

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x8c6e438), parent's thread is MainThread(0x8c794c0), current thread is QThread(0x3e5190)


В общем не понимаю я всей этой архитектуры... А Qt написали такие скудные примеры =\
Помогите кто чем сможет... На данный момент это простенький чат пишется для тестирования...

UPD:
Processing Qt 4.5 moveToThread() или метод “Мюнхгаузена”

Это сообщение отредактировал(а) SwordOfDeath - 19.7.2009, 11:37
PM MAIL   Вверх
null56
Дата 19.7.2009, 22:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



попробую догадаться, но не совсем понял, где что создается
1) tcpServerConnection - это объект переменная член класса? создается где? в функции run() или нет?
2) если tcpServerConnection создается в функции run, то ты НЕ можешь делать вот так из основного потока
Код

thread->tcpServerConnection->setSocketDescriptor(socketDescriptor)

Так как за объект класса QTcpSocket отвечает дочерний поток, ты должен ему передавать дескриптор сокета, средствами сигналов - слотов или посылая сообщения фунцией postEvent (sendEvent), где можешь передавать сам файловый дескриптор
3) По поводу этого я не уверен, 
Код

А если переношу QTcpSocket в новосозданный поток (thread->tcpServerConnection.moveToThread(thread)), причем ругается в exec():

а именно, где ты создаешь объект сокета... могу лишь предположить, что ты назначаешь родителя объекту tcpServerConnection, что делать, при использовании moveToThread НЕЛЬЗЯ
4) Хорошо бы привезти код, не весь, а только концептульный твоей проблеме, было бы нагляднее


Это сообщение отредактировал(а) null56 - 19.7.2009, 23:04
PM MAIL   Вверх
SABROG
Дата 19.7.2009, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Я бы не рекомендовал использовать не свои классы с методом moveToThread. Этот метод за раз переносит только один объект, если при этом объект создает внутри себя или пытается использовать другие QObject'ы, то без их переноса возникнет проблема.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
SwordOfDeath
  Дата 20.7.2009, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Таксь последовал вашим замечаниям по поводу moveToThread, и теперь создаю tcpServerConnection в run()... Таким образом мне уже не нужно его куда либо переносить.

Покопавшись разобрался почему ругается в exec() созданного потока;
Я связываю сигнал из потока с слотом из главного потока:
Код

connect(thread, SIGNAL(incMessage(int, QByteArray)), this, SLOT(parseMessage(int, QByteArray)));


В мануале написано что Сигнал-Слот без проблем работает между потоками... А тут вот грабли...
Или может это грабли с передаваемыми данными? Как правильно это делать?
PM MAIL   Вверх
SABROG
Дата 20.7.2009, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Проверь не пишется ли в консоль что-то связанное с QByteArray и qRegisterMetatype.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
SwordOfDeath
Дата 20.7.2009, 12:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Вот полный вывод начиная от старта и заканчивая закрытием:
Код

Lowest section in C:\WINDOWS\system32\xpsp2res.dll is .rsrc at 00011000
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x3ed698), parent's thread is ChatHostThread(0x3ee8e8), current thread is QThread(0x3e5190)
QThread: Destroyed while thread is still running



Это сообщение отредактировал(а) SwordOfDeath - 20.7.2009, 12:12
PM MAIL   Вверх
null56
Дата 20.7.2009, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Цитата(SwordOfDeath @ 20.7.2009,  12:12)
Вот полный вывод начиная от старта и заканчивая закрытием:

я имел в виду исходный код твоей программы
Цитата

QThread: Destroyed while thread is still running

это происходит потому, что программа закрывается до того, как завершатся дочерние потоки... подождать надо завершения
PM MAIL   Вверх
SwordOfDeath
  Дата 20.7.2009, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Привожу частичный код
Код

void ChatHostServer::incomingConnection(int socketDescriptor)
{
    ChatHostThread *thread = new ChatHostThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(thread, SIGNAL(incMessage(int, QByteArray)), this, SLOT(parseMessage(int, QByteArray)));
    thread->start();
}


Код

void ChatHostThread::run(){
    tcpServerConnection = new QTcpSocket;
    if (!tcpServerConnection->setSocketDescriptor(socketDescriptor)) {
        emit error(tcpServerConnection->error());
        return;
    }
    connect(tcpServerConnection, SIGNAL(readyRead()), this, SLOT(incomingData()));
    exec();
}

Как видно он ничем не отличается от примеров Qt... кроме как запуском eventloop'a и связыванием сигнал-слота в разных потоках.


UPD:
Двигаюсь дальше... Ошибку вызывает не сам Сигнал-Слот и не его параметры... А код который описан в слоте... Так как будто этот код вызывается прямо в контексте потока который сгенерил сигнал... Указание Qt::QueuedConnection результата не дали...


Это сообщение отредактировал(а) SwordOfDeath - 20.7.2009, 19:33
PM MAIL   Вверх
null56
Дата 20.7.2009, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Я набил пример тебе маленький, где использую ТВОЙ код...
Сервер висит в ожидании, при поступлении нового подключения создает объект нити, передавая туда дескриптор.
Клиент, коннектится к серверу, как только подлючается в слоте onConnected посылает строку серверу... 
Все работает без проблем...
цепляй прикрепленный файл, там отдельно собирешь клиента и сервера, запустишь и посмотришь, правильно  ли я понял твою идею и твой вопрос

Присоединённый файл ( Кол-во скачиваний: 37 )
Присоединённый файл  chat.tar.bz2 1,63 Kb
PM MAIL   Вверх
null56
Дата 20.7.2009, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



ЗЫ: естетсвенно, чтобы не было
Цитата

QThread: Destroyed while thread is still running

ты сам должен позаботиться о том, чтобы завершить eventloop и дочерний поток, перед тем, как завершится основной поток

Присоединённый файл ( Кол-во скачиваний: 42 )
Присоединённый файл  chat.tar.bz2 1,63 Kb
PM MAIL   Вверх
SwordOfDeath
Дата 20.7.2009, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Спасибо огромное за помощь... Но кажется это не решит моей проблемы...
Так как вы в parseMessage(int value, QByteArray msg) вызываете qDebug() которому не важно в каком потоке он вызван...
Мне же в этой функции нужно работать с данными и вызывать функции главного потока...
PM MAIL   Вверх
null56
Дата 20.7.2009, 19:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



Я не понимаю, приведи пример, того, чего ты хочешь
Код

SLOT(parseMessage(int, QByteArray)));

слот будет обрабатываться в основном потоке, так как он создан вместе с оъектом ChatHostServer в основном потоке

Добавлено через 3 минуты и 53 секунды
Цитата

А код который описан в слоте... Так как будто этот код вызывается прямо в контексте потока который сгенерил сигнал... Указание Qt::QueuedConnection результата не дали...

приведи пример кода в слоте
PM MAIL   Вверх
SwordOfDeath
Дата 20.7.2009, 21:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Продвинулся дальше...
При прихождении данных я передаю сообщение в основной поток... где его обрабатываю и отсылаю ответ назад в поток который прислал данные... и уже там слот:
Код

void ChatHostThread::sendMessage(QByteArray message){
    tcpServerConnection->write(message);
}

Вот он то и создает ошибку... Чувствую себя паршиво что не отдебажил все как положено до самого конца =\

Также эту же ошибку вызывает добавление tcpServerConnection->write(tcpServerConnection->readAll()); в слот void ChatHostThread::incomingData()

Проверил на вашем примере... Та же ошибка при попыке отправки сообщения с сервера клиенту...

Это сообщение отредактировал(а) SwordOfDeath - 20.7.2009, 21:34
PM MAIL   Вверх
null56
Дата 20.7.2009, 21:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 6
Всего: 12



НИИИИИИИЗЗЯЯЯЯЯЯЯЯЯЯЯЯЯЯЯ, написал же чуть выше про подобное...
Объект класса QTcpSocket обслуживается дочерней нитью и лезть к этому объекту из другой нити, нИИИИИИИИзЯ...
Можно передать эти данные дочерней ните, которая уже будет отсылать их твоему объекту сокету...
примерно так дополню твой класс ChatHostThread
Код

// вот он сигнал, который будет передавать твое сообщение объекту в дочернем потоке
signals:
     void writeToSocket(QByteArray);

// функция сгенерит сигнал, который будет цепляться к слоту сокета, созданного в дочернем потоке
void ChatHostThread::sendMessage(QByteArray message)
{
    emit writeToSocket(message);
}


Функция run()
Код

void ChatHostThread::run(){
    tcpServerConnection = new QTcpSocket;
    if (!tcpServerConnection->setSocketDescriptor(socketDescriptor)) {
        emit error(tcpServerConnection->error());
        return;
    }
    connect(tcpServerConnection, SIGNAL(readyRead()), this, SLOT(incomingData()));
    // ВОТ ТУТ ЦЕПАНИ СЛОТ
    connect(this, SIGNAL(writeToSocket(QByteArray)), tcpServerConnection, SLOT(onWrite(QByteArray)));
    exec();
}


Далее унаследуй класс от QTcpSocket и в функции run создавай уже его, чтобы определить этот недостающий слот... например
Код

class TcpSocket : public QTcpSocket
{
.............
//а вот он слот, который ты цепанешь в функции run(), он будет работать, как и весь объект в дочернем потоке
public slots:
        void onWrite(QByteArray message)
        {
               // и уже вот тут ты точно будет в дочернем потоке
              write(message);
        }
.............
};


Переменную член класса так же делаешь своим TcpSocket и в функции run создаешь его же...
Код

void ChatHostThread::run(){
    tcpServerConnection = new TcpSocket;


Теперь через такую Ж мы получили следующее:
вызов функции sendMessage(QByteArray message) (даже если это слот) сгенерит сигнал, слот которого обработается в дочернем потоке объекта нашего класса TcpSocket
во... )

Это сообщение отредактировал(а) null56 - 20.7.2009, 21:45
PM MAIL   Вверх
SwordOfDeath
  Дата 20.7.2009, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 16.10.2007

Репутация: нет
Всего: нет



Так я так и делаю!...
Не лезу я к этому объекту из другой нити... Я все через Сигнал-Слоты гоняю...
И опять же проблему можно повторить и в вашем примере:
Добавив в ChatHostThread :: incomingData()
Код

m_TcpServerConnection->write(msg);

Хм.. но данные отправляются...
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0587 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.