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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Обмен данными между потоками  (Прочитано 15355 раз)
andrew.k
Гость
« : Октябрь 28, 2010, 13:09 »

У меня есть несколько потоков.
Хочу реализовать передачу данных от одного потока к другому хочу реализовать так:
Код:
KProtocolThread: public QThread
{
public:
  void sendCommand( int code, const QByteArray &data );
protected slots:
  void sendCommandImplementation( int code, const QByteArray &data );
};

void KProtocolThread::sendCommand( int code, const QByteArray &data )
{
  QMetaObject::invokeMethod( this, "sendCommandImplementation", Qt::QueuedConnection,
              Q_ARG( int, code ),
              Q_ARG( QByteArray, data ) );
}


Для использования, в основном потоке вызываю, thread->sendCommand (где thread указатель на экземпляр класса потока), что помещает вызов слота sendCommandImplementation в очередь событий потока.

Вопросы:
1. Адекватный ли это способ.
2. Какие есть подводные камни?
3. Очень важно. События в очереди обрабатываются в том же порядке в котором поступили или могут в произвольном?
Записан
Denjs
Гость
« Ответ #1 : Октябрь 28, 2010, 22:49 »

в сторону... и чем вас не устраивает согнал-слотовое оединение объектов находящихся в разных потоках? Непонимающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Октябрь 29, 2010, 14:26 »

Вопросы:
1. Адекватный ли это способ.
2. Какие есть подводные камни?
3. Очень важно. События в очереди обрабатываются в том же порядке в котором поступили или могут в произвольном?
3) Ну если "вообще о событиях в очереди" - то нет, могут и не в том же. Но для посланных сигналовю как Вы делаете - да, в том же.  По поводу 1) и 2): способ вполне адекватный, но производительностью не отличается, особенно учитывая что массивы все равно будут копироваться. Через сигналы (вместо invokeMethod) можно записать проще (хотя это дело вкуса).
Записан
andrew.k
Гость
« Ответ #3 : Ноябрь 01, 2010, 04:13 »

Вопросы:
1. Адекватный ли это способ.
2. Какие есть подводные камни?
3. Очень важно. События в очереди обрабатываются в том же порядке в котором поступили или могут в произвольном?
3) Ну если "вообще о событиях в очереди" - то нет, могут и не в том же. Но для посланных сигналовю как Вы делаете - да, в том же.  По поводу 1) и 2): способ вполне адекватный, но производительностью не отличается, особенно учитывая что массивы все равно будут копироваться. Через сигналы (вместо invokeMethod) можно записать проще (хотя это дело вкуса).
через сигналы у меня сделано в одну сторону. в другую через invokeMethod. Потому что мне нужно посылать данные конкретному потоку. Через сигналы это сделать невозможно.
Записан
Amigo_sa
Гость
« Ответ #4 : Ноябрь 01, 2010, 11:17 »

через сигналы у меня сделано в одну сторону. в другую через invokeMethod. Потому что мне нужно посылать данные конкретному потоку. Через сигналы это сделать невозможно.
Почему невозможно, вы же конкретный объект подписываете на сигнал, т.е. вы можете
1. ненужные вам потоки на время заблокировать для получения сигналов (blockSignals)
2. использовать разные сигналы для каждого потока.
3. В сигнале передавать параметр - ID нужного потока, слот будет проверять, "свое" ли сообщение ему пришло..
Записан
andrew.k
Гость
« Ответ #5 : Ноябрь 02, 2010, 21:41 »

через сигналы у меня сделано в одну сторону. в другую через invokeMethod. Потому что мне нужно посылать данные конкретному потоку. Через сигналы это сделать невозможно.
Почему невозможно, вы же конкретный объект подписываете на сигнал, т.е. вы можете
1. ненужные вам потоки на время заблокировать для получения сигналов (blockSignals)
ужоснах!
Цитировать
2. использовать разные сигналы для каждого потока.
а как динамически создать N сигналов?
Цитировать
3. В сигнале передавать параметр - ID нужного потока, слот будет проверять, "свое" ли сообщение ему пришло..
Это мягко говоря очень неоптимально. Один сигнал получат сразу все потоки, хотя предназначается он только для одного.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Ноябрь 02, 2010, 22:09 »

Это мягко говоря очень неоптимально. Один сигнал получат сразу все потоки, хотя предназначается он только для одного.
Сигнал получает объект (а не нитка). Если задан (явно или нет) QueuedConnection то сигнал будет доставляться через eventLoop той нитки которой этот объект "принадлежит". Эту принадлежность можно установить (moveToThread). Конечно надо крутить eventLoop для ниток, но как я понял, у Вас это есть. Неясно в чем проблема и зачем усложнять себе жизнь используя invokeMethod.
Записан
andrew.k
Гость
« Ответ #7 : Ноябрь 03, 2010, 02:26 »

Это мягко говоря очень неоптимально. Один сигнал получат сразу все потоки, хотя предназначается он только для одного.
Сигнал получает объект (а не нитка). Если задан (явно или нет) QueuedConnection то сигнал будет доставляться через eventLoop той нитки которой этот объект "принадлежит". Эту принадлежность можно установить (moveToThread). Конечно надо крутить eventLoop для ниток, но как я понял, у Вас это есть. Неясно в чем проблема и зачем усложнять себе жизнь используя invokeMethod.

Сервер создает на каждое вход подключение поток. На другой стороне создается один поток на исходящее подключение.
Вход и исход потоки один и тот же класс (работают одинаково).
Когда поток "насобирал" необходимое ему кол-во данных он эмитит сигнал с данными (сообщение).
Все сигналы от потоков сервера связаны с одинм его слотом. Тут проблем нет. Легко определить от кого пришли данные.
Но теперь мне нужно этому потоку с которого пришли данные послать ответ?
Как передать данные нужному потоку сигналами и слотами?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Ноябрь 03, 2010, 15:04 »

Но теперь мне нужно этому потоку с которого пришли данные послать ответ?
Как передать данные нужному потоку сигналами и слотами?
Ну в любом случае Вам известен объект которому нужно передать. Я бы попробовал так:

- у объекта сделал ф-цию которая посылает сигнал самому себе (QueuedConnection).
- сервер просто вызывает эту ф-цию объекта (в нитке исполнения сервера), ф-ция кладет event в тот eventLoop что надо
- если есть опасность что 2 или более сервера вызовут этот метод, защититься мутексом в начале метода
Записан
andrew.k
Гость
« Ответ #9 : Ноябрь 03, 2010, 15:52 »

Но теперь мне нужно этому потоку с которого пришли данные послать ответ?
Как передать данные нужному потоку сигналами и слотами?
Ну в любом случае Вам известен объект которому нужно передать. Я бы попробовал так:

- у объекта сделал ф-цию которая посылает сигнал самому себе (QueuedConnection).
- сервер просто вызывает эту ф-цию объекта (в нитке исполнения сервера), ф-ция кладет event в тот eventLoop что надо
Собственно я так и сделал. через invokeMethod.
Как можно послать сигнал самому себе?
делать emit signal, а к сигналу коннектить слот? Мне кажется это через Опу. И по сути делать то, что делает invokeMethod, за исключением того, что invokeMethod - это логично и понятно, а эмит сигнала для самого себя - это странно.
Цитировать
- если есть опасность что 2 или более сервера вызовут этот метод, защититься мутексом в начале метода
Во-первых, двух серверов нет. Каждый сервер управляет только своими собственными потоками.
Во-вторых, кто бы не вызывал эту функцию, она просто помещает в очередь вызов слота. Не вижу в этом опасности.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 03, 2010, 17:37 »

делать emit signal, а к сигналу коннектить слот? Мне кажется это через Опу. И по сути делать то, что делает invokeMethod, за исключением того, что invokeMethod - это логично и понятно, а эмит сигнала для самого себя - это странно.
А что тут странного? С QueuedConnection cигнал - тот же postMessage. А вызов postMessage самому себе встречается повсеместно (хоть в том же Вындоуз). "Оформление" получается приятнее, connect засунуть в конструктор, ну и просто позвать метод-сигнал, напр так
Код:
theProtocolThread->PostCommand(code, data);
Так что это столь же логично и через то же самое место  Улыбающийся
Записан
andrew.k
Гость
« Ответ #11 : Ноябрь 03, 2010, 18:20 »

делать emit signal, а к сигналу коннектить слот? Мне кажется это через Опу. И по сути делать то, что делает invokeMethod, за исключением того, что invokeMethod - это логично и понятно, а эмит сигнала для самого себя - это странно.
А что тут странного? С QueuedConnection cигнал - тот же postMessage. А вызов postMessage самому себе встречается повсеместно (хоть в том же Вындоуз). "Оформление" получается приятнее, connect засунуть в конструктор, ну и просто позвать метод-сигнал, напр так
Код:
theProtocolThread->PostCommand(code, data);
Так что это столь же логично и через то же самое место  Улыбающийся

Странно тем, что зная что сигнал будет обрабатываться тем же самым объектом. Генерить этот сигнал и внутри самого себя к нему коннектиться, если можно просто в нужном месте положить вызов слота в очередь.
В итоге emit sendCommand( code, data );
заменится на sendCommand( code, data );
Т.е. никакой разницы в использовании.

С другой стороны о вкусах не спорят Улыбающийся По мне так мой метод нагляднее.
Вот например, смотрит другой человек твой хедер. видит там сигнал. он может подумать, что к нему надо коннектиться, что-то с этим делать. читать твои комментарии, чтобы понять как это работает. Можно по ошибке или непониманию (в случае другого программиста) сделать дисконнект и нарушить логику работы твоего класса.
В моей реализации только одна публичная функция, которая делает, что нужно. Понятно без комментариев. Реализация скрыта и недоступна. Инкапсуляция и ниибет Улыбающийся
Записан
andrew.k
Гость
« Ответ #12 : Ноябрь 03, 2010, 18:43 »

честно говоря я так и не понял как положить вызов слота в очередь при помощи postEvent.
Записан
Akon
Гость
« Ответ #13 : Ноябрь 03, 2010, 22:57 »

QEvent::MetaCall  Улыбающийся
Записан
andrew.k
Гость
« Ответ #14 : Ноябрь 04, 2010, 14:02 »

QEvent::MetaCall  Улыбающийся
И что?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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