34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4

Можете объяснить moveToThread()?

04.05.2018, 15:18. Показов 13076. Ответов 36
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Как я понимаю объект,который перемещают, "уходит" в другой поток весь.
Т.е. this уже будет невалидным и все коннекты будут хоть и верными,
но сигналы будут уходить в никуда.
Что произойдёт с полями объекта?
Если в конструкторе объекта создаю ,например, таймер, то неважно,когда я его законекчу.
До вывода в отдельный поток или после-timeout не сработает.(точнее слот не будет вызван)
Если же создам после сигнала started(QThread) - всё норм.

Для корректной работы надо всегда делать пустой конструктор и дожидаться переноса в другой поток,
а уж потом запускать "полноценный" конструктор?

Если есть тонкости qt4 и qt5, также буду рад пояснениям.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
04.05.2018, 15:18
Ответы с готовыми решениями:

можете объяснить для чего нужно
connect(line,SIGNAL(textChanged(QString)),this,SLOT(TextChanged(QString))); void Window::TextChanged(QString str) { ...

QWebView+movetoThread
Добрый день! Столкнулся со странной ошибкой.(qt 5.5.0) итак имеется сlass CLASS1:publick QObject{ Q_OBJECT CLASS2 *_class2; ...

QUDPSocket + moveToThread
Не могу понять как реализовать данную связку. Если писать this то он ругается, мол нельзя управлять из одного потока если создан в другом....

36
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.05.2018, 16:07
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от saqef Посмотреть сообщение
Если напишем new в новом потоке, объект будет создан уже в новом потоке,не так?
Ты в процессе работы уже после moveToThread() что-то создаёшь? Ну должно быть в новом. И это имеет значение только для потомков QObject.
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
10.05.2018, 16:35  [ТС]
Так в этом и вопрос,я описал в 14 посте.

Если я хочу обращаться к методам мэмбэра моего класса,перенесённого в другой поток,
то мне нужно создавать их(мэмбэры) уже в новом потоке?
0
 Аватар для oxotnik
1665 / 1134 / 80
Регистрация: 21.08.2008
Сообщений: 4,734
Записей в блоге: 1
10.05.2018, 19:00
Цитата Сообщение от nmcf Посмотреть сообщение
Инициализация же до moveToThread()
Да хоть когда, moveToThread не меняет контекст потока, в котором происходит создание таймера (вызов конструктора).
Цитата Сообщение от saqef Посмотреть сообщение
Если я хочу обращаться к методам мэмбэра моего класса,перенесённого в другой поток,
то мне нужно создавать их(мэмбэры) уже в новом потоке?
"Мемберы" создаются автоматически при создании экземпляра объекта.
Если они потокобезопасные, то можно вызывать их откуда хочешь.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.05.2018, 19:29
Цитата Сообщение от oxotnik Посмотреть сообщение
Да хоть когда, moveToThread не меняет контекст потока, в котором происходит создание таймера (вызов конструктора).
Какой ещё контекст? Я о конструкторе говорил.
0
 Аватар для oxotnik
1665 / 1134 / 80
Регистрация: 21.08.2008
Сообщений: 4,734
Записей в блоге: 1
10.05.2018, 21:05
Цитата Сообщение от nmcf Посмотреть сообщение
Какой ещё контекст? Я о конструкторе говорил.
в котором и вызывается этот конструктор
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
11.05.2018, 08:27
Цитата Сообщение от saqef Посмотреть сообщение
Если я хочу обращаться к методам мэмбэра моего класса,перенесённого в другой поток,
то мне нужно создавать их(мэмбэры) уже в новом потоке?
Нет, создавать можешь где угодно. Но родителя для таймера указывать надо явно (т.к. иначе он останется в том же потоке, в котором выполнялась A::A() ):
C++ (Qt)
1
m_timer = new QTimer(this);
Либо и для него тоже выполняй moveToThread + deleteLater
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
11.05.2018, 18:17  [ТС]
Цитата Сообщение от TRam_ Посмотреть сообщение
Но родителя для таймера указывать надо явно
Я думал об этом, но меня смутило The object cannot be moved if it has a parent,а ведь таймер должен "переехать" вместе с А.

Добавлено через 2 минуты
Или все объекты, родителем которых является А, будут автоматически также перемещены в новый поток?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
11.05.2018, 18:25
saqef, там явно написано что именно перемещаемый объект (т.е. который класса A) не должен иметь родителей. А наследников он может иметь сколько угодно.

Changes the thread affinity for this object and its children.
- "принадлежность к потоку поменяют объект и его наследники"

Добавлено через 1 минуту
А
C++ (Qt)
1
m_timer = new QTimer;
эквивалентно
C++ (Qt)
1
m_timer = new QTimer(nullptr);
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
11.05.2018, 18:37  [ТС]
Цитата Сообщение от TRam_ Посмотреть сообщение
эквивалентно
это я понимаю - с моделью знаком.
С Qt понятно - надо всегда указывать родителя.
А с членами, которые не являются наследниками от Qt, как быть?
Всё равно наследоваться от qobject?
Ведь иначе мэмбэры будут существовать в другом потоке.
0
 Аватар для oxotnik
1665 / 1134 / 80
Регистрация: 21.08.2008
Сообщений: 4,734
Записей в блоге: 1
11.05.2018, 19:05
Цитата Сообщение от saqef Посмотреть сообщение
А с членами, которые не являются наследниками от Qt, как быть?
Всё равно наследоваться от qobject?
Ведь иначе мэмбэры будут существовать в другом потоке
Те которые не наследуются от QObject все равно в каком потоке будут, ибо поток определяет контекст, где (если по простому объяснять) будут вызываться слоты объектов, унаследованных от QObject
0
 Аватар для icpu
487 / 365 / 93
Регистрация: 10.03.2011
Сообщений: 1,513
Записей в блоге: 5
11.05.2018, 19:19
А с членами, которые не являются наследниками от Qt, как быть?
saqef, никак. "Мэмбэры" - это просто байты. Их может использовать кто угодно и как угодно.
Давайте разберём базу, в которой у вас проблемы.
Чем отличаются два потока (не Qt) друг от друга? У каждого потока свой набор регистров и свой стек вызовов. Всё остальное - общее. Это означает, что нам, в общем, без разницы, кто запустит конструктор, - они все будут располагаться в общей памяти.
Чем отличаются два потока (Qt)? У каждого Qt потока своя очередь сообщений. Для каждого потока в их общей памяти будет создано по QEventLoop. Каждый поток будет бегать в цикле по своему QEventLoop, пока не получит команду на выход. Бегая в цикле, поток будет брать из очереди сообщений очередное и прогонять его по всем привязанным к нему QObject'ам. Сигналы - это тоже сообщения.
Так вот, когда у QObject'а есть родитель, он берёт сообщения из того же потока, что и родитель, в порядке очереди.
Когда у QObject'а нет родителя, ему принудительно устанавливается тот поток, из которого он был создан.

Теперь о проблеме. Вы выполняете A::A в потоке п1, а A::start в потоке п2. Если вы в потоке п1 создаёте таймер без родителя, а запускаете его явным вызовом из п2, п2 создаёт у себя событие активации таймера и оставляет в своей очереди. Когда наступает момент события, он его прогоняет по своим объектам. Но таймер привязан к п1, а, значит, у п2 нет объектов, которые могут принять это сообщение - и оно утилизируется. Но в самом таймере меняется внутреннее состояние на "запущен", то есть создаётся ситуация неопределённости. Не надо так делать. (И, нет, честных способов "у двух маток сосать" нету. И слава Богу!)

Правильное решение - либо сразу привязать таймер к потоку п2 (не важно, где он будет создан, важно - вызвать moveToThread(п2) перед запуском), либо соединить запуск таймера с каким-либо сигналом из п2.

Добавлено через 4 минуты

Не по теме:

Хотя тут нужно проверять всё по исходникам: в свой ли поток добавляет событие таймер - или в вызвавший; позволяет ли он производить конкурентные вызовы методов или нет, а у меня нет сорцов при себе.

1
 Аватар для oxotnik
1665 / 1134 / 80
Регистрация: 21.08.2008
Сообщений: 4,734
Записей в блоге: 1
11.05.2018, 19:19
через QDebug все видно кто в каком потоке живет:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
TimersOwner::TimersOwner(QObject *parent)
    : QObject(nullptr)
{
    Q_UNUSED(parent);
 
    qDebug() << "current" << thread();
 
    m_timer1 = new QTimer(this);
    m_timer2 = new QTimer();
 
    m_thread = new QThread;
 
    m_timer3 = new QTimer();
    m_timer3->moveToThread(m_thread);
 
    QObject::connect(m_thread, &QThread::finished, m_thread, &QObject::deleteLater);
 
    QObject::connect(m_thread, &QThread::started, this, &TimersOwner::onThreadStarted);
 
    moveToThread(m_thread);
    m_thread->start();
 
}
 
TimersOwner::~TimersOwner()
{
    m_thread->quit();
}
 
void TimersOwner::onThreadStarted()
{
    qDebug() << "this" << this->thread();
    qDebug() << "m_timer1" << m_timer1->thread();
    qDebug() << "m_timer2" << m_timer2->thread();
    qDebug() << "m_timer3" << m_timer3->thread();
}
вывод:

current QThread(0x6041e0)
this QThread(0x6058a0)
m_timer1 QThread(0x6058a0)
m_timer2 QThread(0x6041e0)
m_timer3 QThread(0x6058a0)
0
2737 / 892 / 331
Регистрация: 10.02.2018
Сообщений: 2,136
11.05.2018, 21:37
Цитата Сообщение от icpu Посмотреть сообщение
Хотя тут нужно проверять всё по исходникам: в свой ли поток добавляет событие таймер - или в вызвавший; позволяет ли он производить конкурентные вызовы методов или нет, а у меня нет сорцов при себе.
У меня в консоле ошибка выдаётся при попытке запустить/остановить таймер из левого потока. Скорее тут просто ограничение на использование функции запуска таймера. Таймер может запускаться/останавливаться только из правильного потока. Обработка же сигнала таймера может выполняться в любом потоке.
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
14.05.2018, 11:18  [ТС]
Цитата Сообщение от icpu Посмотреть сообщение
вызвать moveToThread(п2) перед запуском
Почему?
Ведь по докам при перенесении в другой поток просто таймер сбрасывается.
Логика же не нарушится.
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
01.06.2018, 14:48  [ТС]
Можете ещё подсказать насчёт переноса не qt-шных сущностей.

Так работает:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A::A
{
    ...
    this->moveToThread(m_thread);
    connect(m_thread,&QThread::started,this,&A::start);
    m_buffer=new uchar[size];
    ...
    m_thread->start();
}
 
void A::start()
{
    m_struct.pointer=m_buffer;
    func(m_struct);
}
Всё в порядке,вне зависимости от того как я обращаюсь к памяти:напрямую или через структуру.
Но если я создам структуру в конструкторе,то при обращении к буферу ошибка обращении.
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A::A
{
    ...
    this->moveToThread(m_thread);
    connect(m_thread,&QThread::started,this,&A::start);
    m_buffer=new uchar[size];
    m_struct.pointer=m_buffer;
    ...
    m_thread->start();
}
 
void A::start()
{
    func(m_struct);
}
даже если в func буду напрямую обращаться к m_buffer.
Что происходит?
Ведь:
Цитата Сообщение от icpu Посмотреть сообщение
"Мэмбэры" - это просто байты. Их может использовать кто угодно и как угодно.
0
 Аватар для icpu
487 / 365 / 93
Регистрация: 10.03.2011
Сообщений: 1,513
Записей в блоге: 5
01.06.2018, 15:41
Не знаю, saqef, сам мне скажи, что это у тебя за структуры, и в каком месте стека вызовов с какой ошибкой приложение падает. Иначе зачем тебе отладчик?

Самое наивное предположение: m_struct - нечто большее, чем указатель на массив, и что-то остаётся не инициализированным. Казалось бы, смех да и только, но тут не всё так однозначно. А если хотите конкретики, делайте минимальный синтетический тест, повторяющий это поведение.
0
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4
01.06.2018, 17:25  [ТС]
Повторяется всегда.
Структура моя.
Самая простая: указатель на массив и его размеры.
Вылет происходит когда пытаюсь обратиться к m_buffer[0],но только если создаётся в конструкторе.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.06.2018, 17:25

О работе с moveToThread
Всем привет! В общем такой вопрос, создаю поток, заталкиваю туда через сигнал loop - процесс. Сам процесс идет, но после этого я не могу...

Использование moveToThread
при выполнении comConnect() получаю ошибку QObject: Cannot create children for a parent that is in a different thread. (Parent is...

Использование функции moveToThread
Доброго времени суток. Не знал, как точно озаглавить эту тему, поэтому объясню здесь. У меня есть динамический массив произвольного...

Можете объяснить
пожалуйста как работает

Можете объяснить
Можете объяснить действия с начало тело программы { printf(&quot;предпоследняя цифра равна %d\n&quot;, n / 10 % 10);... и до } #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
37
Ответ Создать тему
Опции темы

Новые блоги и статьи
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru