Могу ли я использовать взаимодействие с данными QAbstractTableModel в QThread?
Я знаю, что мы не можем использовать GUI-взаимодействие в не-GUI потоках (QThread
). Но я не знаю, можем ли мы взаимодействовать с моделью (QAbstractItemModel
) в темах и если True, то как это сделать правильно?
Я честно искал что-то об этом в Google и на SO, и, похоже, нет соответствующих ответов на мой вопрос.
1 ответ
Что вы подразумеваете под "взаимодействовать с моделью"? Если вы имеете в виду, что вы хотите получить доступ к модели из нескольких потоков, напрямую манипулируя ею, то вы должны сериализовать доступ к модели. Поскольку в модели так много методов, я бы посоветовал вам не добавлять мьютекс в модель - это было бы очень утомительно и подвержено ошибкам, так как было бы слишком легко забыть блокировщик мьютекса. Вместо этого используйте тот факт, что ваша модель наследует QObject и, таким образом, может принимать события.
- Ваш поток графического интерфейса напрямую обращается к модели.
- Другие потоки взаимодействуют с моделью, публикуя в ней события (и, возможно, получая ответные события).
- Поток графического интерфейса будет обрабатывать эти события последовательно с любым другим доступом, таким образом защищая вашу модель от одновременного доступа.
Другие потоки могут, конечно, получать ответы от модели - также через события. У вас будет два базовых класса событий: Request
класс, который используется для запроса вещей из модели, а затем будет Response
базовый класс событий, который модель будет использовать для ответа. Класс Request должен иметь QObject* sender
член, так что модель будет знать, в какой объект QObject отправлять событие ответа. Вы, вероятно, захотите, чтобы и запрос, и ответ имели одинаковый идентификатор (скажем, последовательное увеличение int), чтобы запросы и ответы могли совпадать.
Вы должны реализовать весь многопоточный код, который взаимодействует с моделью через события, а не путем переопределения QThread::run()
, но внутри QObject. После того, как вы создаете QObject
Просто перенесите его в отдельную ветку. Реализация QThread по умолчанию run()
будет вращать цикл обработки событий, чтобы ваш QObject выполнялся, если к нему есть какие-либо события, сигналы или таймеры. Таймер нулевой длительности - это способ постоянно держать поток занятым, но убедитесь, что вы не выполняете слишком много обработки за один раз, иначе вы задержите обработку входящих событий.
Вы также можете использовать сигналы и слоты, но вы не можете вызывать их напрямую, вы можете только:
connect()
им,- вызвать их через
QMetaObject::invokeMethod
сQt::QueuedConnection
, - вызывать их через функтор (скажем, лямбду), выполняемый в контексте основного потока; посмотрите этот ответ, чтобы узнать, как это сделать.
За кулисами, когда вы подключаете сигналы к слотам объектов QObject, которые находятся в отдельных потоках, Qt создает соединение, которое маршалирует каждый сигнал в QMetaCallEvent
, а затем демарширует его в потоке, в котором находится объект QObject с целевым слотом.