Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.86/64: Рейтинг темы: голосов - 64, средняя оценка - 4.86
34 / 36 / 17
Регистрация: 16.04.2017
Сообщений: 478
Записей в блоге: 4

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

04.05.2018, 15:18. Показов 13020. Ответов 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
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,132
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
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru