LINUX.ORG.RU

Qt4/5 QObject в потоке - вызов метода


0

3

Допустим, есть класс наследованный от QObject и он живёт в QThread. Потоко-безопасно работать с таким классом через сигналы-слоты/InvokeMethod с QueuedConnection. Как только мы где-то вызываем, хоть в одном месте, метод/слот напрямую и он модифицирует общие данные - то мы должны вообще везде обложиться мьютексами где эти данные потом читаются.

Хотелось бы уйти от использования мьютексов, а работать когда все слоты вызываются в контексте своего потока. Так удобнее и надежнее (от дедлоков) работать.

Есть ли макросы или иные способы упростить работу с QueuedConnection, или придется делать методы-обертки, внутри которых будет жить emit или InvokeMethod?

ЗЫ Я уже создавал подобную тему, в ней я понял что проблема существует - вызов напрямую в контексте вызывающего треда. Теперь бы узнать как упростить это дело.

Чтобы вызвать метод в своем треде можно сделать так:

bool Class::do() {
    QTimer::singleShot(0, this, SLOT(do_intern()));
}

Rubbiroid
()
Ответ на: комментарий от asaw

Суть интересующей проблемы: какая часть кода короче

slot_add_host(host);
или
void ping2::add_host(QHostAddress remote_host)
{
	QMetaObject::invokeMethod(this, "slot_add_host", Qt::QueuedConnection, Q_ARG(quint32, remote_host.toIPv4Address()));
}
?

Хотелось бы сократить код, может MOC дает некий механизм для упрощения? Или это единственный способ? Причем надо будет городить дублирующий метод?

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

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Можно всю предысторию ещё раз понятным языком без ужимок? В чем заключается проблема с

Auto Connection (default) If the signal is emitted in the thread which the receiving object has affinity then the behavior is the same as the Direct Connection. Otherwise, the behavior is the same as the Queued Connection."

?

asaw ★★★★★
()
Ответ на: комментарий от asaw

Можно всю предысторию ещё раз понятным языком без ужимок?

КРАТКО: invokeMethod _рабочее_ решение, НО много букаф писать при вызове. Так яснее? Тупо много кода.

Так надо писать сначала слот, потом метод по его вызовы через invokeMethod. Неужели не очевидно что я хочу/надеюсь что есть?

ЗЫ С сигналами-слотами проблемы НЕТ. Просто надо объявлять сигналы, а это лишний код.

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Так надо писать сначала слот, потом метод по его вызовы через invokeMethod. Неужели не очевидно что я хочу/надеюсь что есть?

Нет, не очевидно. Более того, многие кажущиеся очевидными проблемы перестают быть проблемами после того, как их четко описывают :)

Просто надо объявлять сигналы, а это лишний код.

ну уж сигнал то объявить - вообще минимум телодвижений.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от MikeDM

И шашечки и ехать ^_^ Просто мне показалось что это очевидное место для того чтобы облепить такой сценарий на уровне MOC...

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Не нужно в обычном приложении использовать QMetaObject::invokeMethod и вообще обращаться к QMetaObject. Эти классы для этого не предназначены - об этом в документации прямо написано.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от asaw

Не нужно в обычном приложении ... обращаться к QMetaObject.

А как тогда делать enum <-> String? Писать самому switch-case? А нафига, если он уже есть.

Rubbiroid
()
Ответ на: комментарий от I-Love-Microsoft

А чем сигналы и слоты не устраивают? Это же основная парадигма в кьюте.

MikeDM ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Какая у тебя ситуация? 1: Поток А вызывает МетодБ из потока Б. МетодБ должен выполняется в контексте потокаА. Только 1 одновременно возможное выполнение методаБ (synchronized из Java).

2: Поток А вызывает МетодБ из потока Б. МетодБ должен выполнятся в контексте потокаБ.

Если ситуация 1, то используй сигнал/слот вызов. Если 2 - то то, что я написал вначале.

Rubbiroid
()
Ответ на: комментарий от I-Love-Microsoft

К.О. сообщает, что MOC & QMeta* - реализация отражения для С++, сделанная именно для сигналов/слотов в Qt. Поэтому либо использовать эти сигналы/слоты, либо уж использовать альтернативные подходы на чистом C++, что, вообще говоря, вполне возможно. libsigc++ - как пример.

asaw ★★★★★
()
Ответ на: комментарий от Rubbiroid

Большой вопрос ещё зачем вообще это делать. Но если уж совсем лень и очень нужно, то по крайней мере это можно сделать с помощью шаблонов так, чтобы реализацию можно было потом поменять с минимальными потерями.

asaw ★★★★★
()
Ответ на: комментарий от asaw

Большой вопрос ещё зачем вообще это делать

Например: Есть файл с описание внутреннего устройства плиски. У примитивов есть тип. Этот тип в C++ классе - enum. И вот из текста надо получить этот enum. А потом наоборот, enum в текст, при сохранении в такой же файл. Сделать для каждого примитива свой класс бред, т.к. примитивов около 1000 и кроме как списком входов/выходов они ничем не различаются. Точнее их внутренние различия не нужны.

с помощью шаблонов

Видел где-нить готовое решение? А то я бы хотел вынести enum из класса, а тогда не будет QMetaEnum'a.

Rubbiroid
()
Ответ на: комментарий от Rubbiroid

Видел где-нить готовое решение? А то я бы хотел вынести enum из класса, а тогда не будет QMetaEnum'a.

Без интроспекции или её подобия именно это (enum <-> string) кмк не сделаешь никак. Соответсвенно - либо Qt + moc, как общее решение, либо макросы вроде этого: http://www.codeproject.com/Articles/318690/C-11-Non-intrusive-enum-class-with...

Либо вообще заменить enum на более сложный тип, который будет играть ту же роль + поддерживать сериализацию в строку и обратно. С C++11 это должно быть легко.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.