Russian Qt Forum
Ноябрь 23, 2024, 22:55 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Многопоточное использование QUdpSocket  (Прочитано 11719 раз)
Luck
Гость
« : Сентябрь 10, 2010, 15:03 »

Здравствуйте.
Возникла сложность при использовании QUdpSocket.
В приложении 3 потока:
1) поток, в котором выполняется функция main;
2) поток (унаследован от QThread), отправляющий данные через QUdpSocket;
3) поток (унаследован от QThread), принимающий данные через QUdpSocket.

При записи данных из потока main все замечательно: данные отправляются без ошибки, ответ приходит. При попытке отправки данных из 2го потока (даже если выполнять точно такие же действия, что в main-потоке) происходит ошибка (функция QUdpSocket::writeDatagram возвращает -1).

Действия выполняю следующие:

void CThread::f()
{
     QUdpSocket* udpSocket = new QUdpSocket();
     udpSocket->bind(QHostAddress::LocalHost, 7755);
     QByteArray ba = new QByteArray("asdf");
     udpSocket->writeDatagram(ba,QHostAddress::LocalHost,7756);     
}

С протоколом UDP я работаю первый раз, прошу сильно не ругаться Подмигивающий Подскажите, пожалуйста, в чем дело и как исправить?
Записан
Denjs
Гость
« Ответ #1 : Сентябрь 10, 2010, 15:13 »

может быть свзяно с этим ?:
Цитировать
The QUdpSocket class provides a UDP socket.
...
Note: All functions in this class are reentrant.
Reentrancy and Thread-Safety:
Цитировать
Throughout the documentation, the terms reentrant and thread-safe are used to mark classes and functions to indicate how they can be used in multithread applications:

A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.
A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.

Вы с одним объектом работаете из разных потоков? и как с данными?
Записан
BRE
Гость
« Ответ #2 : Сентябрь 10, 2010, 15:14 »

Хотелось бы увидеть как выглядит весь класс CThread и как запускается этот поток.
Записан
Luck
Гость
« Ответ #3 : Сентябрь 10, 2010, 15:22 »

То, что класс QUdpSocket - не ThreadSafe - это я знаю, но это имело бы значение, если бы я использовал один и тот же сокет в разных потоках или одни и те же данные. Однако, ошибка возникает даже при создании сокета и нахождении данных в экземпляре потока CThread.

Выложить полностью класс CThread возможности, к сожалению, нет.
Записан
BRE
Гость
« Ответ #4 : Сентябрь 10, 2010, 15:27 »

Выложить полностью класс CThread возможности, к сожалению, нет.
Секретная разработка? Смеющийся

Ладно, а откуда вызывается метод f()?
Записан
Luck
Гость
« Ответ #5 : Сентябрь 10, 2010, 15:30 »

Метод f вызывается из метода run потока CThread
Записан
BRE
Гость
« Ответ #6 : Сентябрь 10, 2010, 15:50 »

Метод f вызывается из метода run потока CThread
Наверно проще будет просто кусок кода.
Поток отправляет сообщение (переделал пример broadcastsender):
Код
C++ (Qt)
class Thread : public QThread
{
   Q_OBJECT
 
public:
   Thread();
 
protected:
   void run();
 
private slots:
   void broadcastDatagram();
 
private:
   QUdpSocket *udpSocket;
   int messageNo;
};
 

Код
C++ (Qt)
Thread::Thread()
   : QThread( 0 ), messageNo( 1 )
{
   moveToThread( this );
}
 
void Thread::run()
{
   udpSocket = new QUdpSocket;
 
   QTimer timer;
   connect( &timer, SIGNAL( timeout() ), SLOT( broadcastDatagram() ) );
   timer.start( 1000 );
 
   exec();
}
 
void Thread::broadcastDatagram()
{
   QByteArray datagram = "Broadcast message " + QByteArray::number( messageNo );
   udpSocket->writeDatagram(datagram.data(), datagram.size(),
                            QHostAddress::LocalHost, 45454);
   ++messageNo;
}
 
Записан
Luck
Гость
« Ответ #7 : Сентябрь 10, 2010, 16:01 »

Думаю, проблема в том, что я не использовал метод moveToThread, спасибо.
Записан
Denjs
Гость
« Ответ #8 : Сентябрь 10, 2010, 16:26 »

Код:
Thread::Thread()
    : QThread( 0 ), messageNo( 1 )
{
    moveToThread( this );
}

блин.. вот этот кусок меня радует ... отымей себя сам, простите за аналогии?
помещаем себя, в поток, который собою-же и олицетворяем)

разве не содержимое run() собственно будет выполняться в отдельном потоке? вне зависимости где создан родитель?

не, у меня аналогичное написано в конструкторе (вернее не совсем так: moveToThread( _parent->thread() ); - не помню зачем я это делал - видимо для того, что бы не ругалось на то, что родителя нельзя назначить из другого потока...

но не могли бы вы объяснить подробнее работу данного куска кода? зачем так? в ассистанте и примерах от троллей не нашел чего-то подобного....  Строит глазки
заранее спасибо.
« Последнее редактирование: Сентябрь 10, 2010, 16:29 от Denjs » Записан
BRE
Гость
« Ответ #9 : Сентябрь 10, 2010, 16:43 »

но не могли бы вы объяснить подробнее работу данного куска кода? зачем так? в ассистанте и примерах от троллей не нашел чего-то подобного....
Ну дык, смотрим.  Улыбающийся
Сейчас этой строки нет.  Улыбающийся

Код
C++ (Qt)
int main(...)
{
// Контекст первого потока
Thread *thread = new Thread; // Конструируем объект thread, он пренадлежит контексту первого потока.
}
 

Код
C++ (Qt)
void Thread::run()
{
// Появился контекст второго потока.
 
QTimer timer; // Объект timer принадлежит контексту второго потока.
 
// При соединении сигнала от объекта timer, который принадлежит второму потоку, со слотом объекта thread, который принадлежит первому потоку,
// будет выбран метод передачи сигналов через очередь событий, т.е. когда в потоке сработает таймер сообщение об этом будет помещено в очередь событий
// первого потока, соответсвенно слот будет отрабатывать из очереди первого потока.
// Нам это не нужно! Поэтому мы сообщаем Qt, что мы хотим считать объект thread принадлежащим контексту второго потока.
connect( &timer, SIGNAL( timeout() ), SLOT( broadcastDatagram() ) );
}
 
Записан
Denjs
Гость
« Ответ #10 : Сентябрь 10, 2010, 18:01 »

но не могли бы вы объяснить подробнее работу данного куска кода? зачем так? в ассистанте и примерах от троллей не нашел чего-то подобного....
Ну дык, смотрим.  Улыбающийся
Сейчас этой строки нет.  Улыбающийся

Гы) т.е. все просто потому, что метод занимающийся работой с сетью - есть часть наследника QThread?
ну ок))) просто я "думаю немного по другому" - для меня сделать так - это сешать 2 разнородные сущности. - управление потоком и работа с сетью.
 У меня в программе был бы отдельный класс в котором собрано все сетевое взаимодействие и который полностью висел-бы внутри потока и собственно такого аспекта просто бы не возникало..

ок. В любом случае спасибо за пояснения в работе QThread.
Записан
BRE
Гость
« Ответ #11 : Сентябрь 10, 2010, 18:04 »

У меня в программе был бы отдельный класс в котором собрано все сетевое взаимодействие и который полностью висел-бы внутри потока и собственно такого аспекта просто бы не возникало..
Точно, поэтому я думаю moveToThread( this ) и не добавили по умолчанию в конструктор QThread.
Записан
Sahab
Гость
« Ответ #12 : Сентябрь 10, 2010, 21:44 »

http://labs.trolltech.com/blogs/2010/06/17/youre-doing-it-wrong/
http://blog.exys.org/entries/2010/QThread_affinity.html
...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.423 секунд. Запросов: 21.