Как пользоваться QThread в Qt

В статье рассказывается о неправильном и более правильном способах использования механизма потоков через QThread в Qt.

20.02.2016 2 комментария 19 072 просмотров

В статье рассказывается о неправильном и более правильном способах использования механизма потоков через QThread в Qt.

Содержание

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

Неправильный способ

Самый простой в реализации способ — создать потомка от класса QThread и переопределить метод run . Но обратите внимание, данный способ не соответствует идеологии ООП и многие его не рекомендуют.

Создадим приложение, в котором при нажатии кнопки должна запуститься функция, которая увеличивает счетчик на 1 каждую секунду, а остальное время спит. При этом в textEdit выводится информация о состоянии счетчика.

Внешний вид приложения будет таким:

Если реализовать без дополнительного потока, то наше приложение при нажатии на кнопку просто зависнет и не будет отликаться на наши действия.

Итак, создадим новый класс MyThread.

Что у нас тут есть?

  1. Класс наследуется от класса QThread , а также обладает макросом Q_OBJECT . Без него не будут работать сигналы и слоты.
  2. Конструктор потока теперь принимает параметры, например, имя потока. Таким образом в поток можно передать нужную информацию до его запуска.
  3. Основная деятельность потока реализована в методе run() .
  4. У нас есть сигнал void send(int) , который из потока отправляется при каждом изменении счетчика i в методе run() :

Для того, чтобы сигнал из потока получать в главном потоке, нам нужен слот, который будет данный сигнал принимать и обрабатывать. Поэтому в mainwindow.cpp пропишем слот:

А в mainwindow.h объявим его:

Не забудьте в mainwindow.cpp подключить инклуд:

Теперь в слоте нажатия на кнопку мы можем создать экземпляр нашего слота, соединить слот update и сигнал send , а потом уже запустить наш поток.

Теперь при запуске нашей программы и нажатии на кнопку каждую секунду будет появляться значение счетчика:

Допустим, что вам нужно отправить некоторые данные из главного потока в новый поток, но не с помощью конструктора копии. Тогда вам нужно создать сигнал в главном потоке, а обрабатывающий его слот в новом потоке, то есть сделать всё наоборот, чем в примере выше.

В примере ниже мы добавим переменную int globalVar в класс, которую и поменяем из главного потока.

Обрабатывать сигнал будем слотом receiveGlobalVar(int globalVar) .

И в mainwindow.h добавим сигнал:

Соединяем слот и сигнал (обратите внимание на объявление кто отправитель сигнала, а кто получатель), а потом можем сигнал отправлять:

Вот полный код нажатия на кнопку:

При запуске программы и нажатии на кнопку мы увидим, что сигнал из главного потока в новый поток прошел успешно:

Более правильный способ

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

К тому же, как в примере выше, нам пришлось добавлять переменные в класс (globalVar), чтобы можно было получить к ним доступ из разных методов и слотов данного класса. Это всё не очень красиво и не соответствует духу ООП.

Куда правильнее будет прописать класс с нужным функционалом, создать его экземпляр и запихать его в экземпляр нового потока QThread . Что мы и сделаем.

Источник:http://blog.harrix.org/article/4826