Класс QThread
Класс QThread предоставляет платформонезависимый способ управления потоками. Подробнее...
| Заголовок: | #include <QThread> |
| CMake: | find_package(Qt6 COMPONENTS Core REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Core) |
| qmake: | QT += core |
| Наследует: | QObject |
Типы Public
| перечисление | Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, HighPriority, …, InheritPriority } |
Функции Public
| QThread(QObject *parent = nullptr) | |
| virtual | ~QThread() |
| QAbstractEventDispatcher * | eventDispatcher() const |
| void | exit(int returnCode = 0) |
| bool | isFinished() const |
| bool | isInterruptionRequested() const |
| bool | isRunning() const |
| int | loopLevel() const |
| QThread::Priority | priority() const |
| void | requestInterruption() |
| void | setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) |
| void | setPriority(QThread::Priority priority) |
| void | setStackSize(uint stackSize) |
| uint | stackSize() const |
| bool | wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)) |
| bool | wait(unsigned long time) |
Переопределённые публичные функции
| virtual bool | event(QEvent *event) override |
Слот Public
| void | quit() |
| void | start(QThread::Priority priority = InheritPriority) |
| void | terminate() |
Сигналы
| void | finished() |
| void | started() |
Статические публичные члены
| QThread * | create(Function &&f, Args &&... args) |
| QThread * | currentThread() |
| Qt::HANDLE | currentThreadId() |
| int | idealThreadCount() |
| void | msleep(unsigned long msecs) |
| void | sleep(unsigned long secs) |
| void | usleep(unsigned long usecs) |
| void | yieldCurrentThread() |
Функции Protected
| int | exec() |
| virtual void | run() |
Статические защищённые члены
| void | setTerminationEnabled(bool enabled = true) |
Подробное описание
Объект QThread управляет одним потоком управления в программе. Потоки QThread начинают выполняться в run(). По умолчанию, run() запускает цикл событий, вызывая exec(), и выполняет цикл событий Qt внутри потока.
Вы можете использовать рабочие объекты, перемещая их в поток с помощью QObject::moveToThread().
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
}; Код внутри слота Рабочего объекта затем будет выполняться в отдельном потоке. Однако, вы можете подключать слоты Рабочего объекта к любому сигналу, от любого объекта, в любом потоке. Подключение сигналов и слотов между разными потоками безопасно благодаря механизму, называемому подключением в очереди.
Другой способ заставить код выполняться в отдельном потоке — это наследоваться от QThread и переопределить run(). Например:
class WorkerThread : public QThread
{
Q_OBJECT
void run() override {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
} В этом примере поток завершится после возвращения из функции run. В потоке не будет выполняться цикл событий, если вы не вызовете exec().
Важно помнить, что экземпляр QThread расположен в старом потоке, который его создал, а не в новом потоке, который вызывает run(). Это означает, что все очереди слотов QThread и вызванные методы будут выполняться в старом потоке. Таким образом, разработчик, который хочет вызвать слоты в новом потоке, должен использовать подход с рабочим объектом; новые слоты не следует реализовывать напрямую в подклассе QThread.
В отличие от слотов в очереди или вызываемых методов, методы, вызываемые непосредственно на объекте QThread, будут выполняться в потоке, который вызывает метод. При наследовании от QThread помните, что конструктор выполняется в старом потоке, а run() выполняется в новом потоке. Если переменная-член используется в обеих функциях, то переменная используется из двух разных потоков. Убедитесь, что это безопасно.
Примечание: Необходимо соблюдать осторожность при взаимодействии с объектами в разных потоках. Как общее правило, функции могут вызываться только из потока, который создал объект QThread (например, setPriority()), если документация не указывает иное. Подробнее см. Синхронизация потоков.
Управление потоками
QThread уведомит вас сигналом, когда поток будет запущен() и завершён(), или вы можете использовать isFinished() и isRunning() для запроса состояния потока.
Вы можете остановить поток, вызвав exit() или quit(). В крайних случаях вы можете принудительно прервать выполняющийся поток. Однако это опасно и не рекомендуется. Пожалуйста, прочитайте документацию для terminate() и setTerminationEnabled() для получения подробной информации.
Начиная с Qt 4.8, возможно освободить объекты, находящиеся в потоке, который только что завершился, подключив сигнал finished() к QObject::deleteLater().
Используйте wait(), чтобы заблокировать вызывающий поток, пока другой поток не завершит выполнение (или пока не пройдёт указанное время).
QThread также предоставляет статические, независимые от платформы функции сна: sleep(), msleep() и usleep() позволяют соответственно получить полные секунды, миллисекунды и микросекунды. Эти функции были сделаны общедоступными в Qt 5.0.
Примечание: функции wait() и sleep() в общем случае не нужны, так как Qt — фреймворк на основе событий. Вместо wait() рассмотрите прослушивание сигнала finished(). Вместо функций sleep() рассмотрите использование QTimer.
Статические функции currentThreadId() и currentThread() возвращают идентификаторы текущего потока. Первая возвращает платформенно-специфический идентификатор потока; вторая — указатель QThread.
Чтобы задать имя потоку (как это определяется командой ps -L на Linux, например), можно вызвать setObjectName() перед запуском потока. Если вы не вызываете setObjectName(), имя потока будет именем класса исполняемого типа вашего объекта потока (например, "RenderThread" в случае примера Mandelbrot, так как это имя подкласса QThread). Обратите внимание, что в релизных сборках на Windows это в настоящее время недоступно.
См. также Поддержка потоков в Qt, QThreadStorage, Синхронизация потоков, Пример Mandelbrot, Пример семафоров и Пример условных переменных ожидания.
Документация по типам членов
enum QThread::Priority
Этот тип перечисления указывает, как операционная система должна планировать вновь созданные потоки.
| Константа | Значение | Описание |
|---|---|---|
QThread::IdlePriority |
0 |
планируется только тогда, когда другие потоки не выполняются. |
QThread::LowestPriority |
1 |
планируется реже, чем LowPriority. |
QThread::LowPriority |
2 |
планируется реже, чем NormalPriority. |
QThread::NormalPriority |
3 |
по умолчанию приоритет операционной системы. |
QThread::HighPriority |
4 |
планируется чаще, чем NormalPriority. |
QThread::HighestPriority |
5 |
планируется чаще, чем HighPriority. |
QThread::TimeCriticalPriority |
6 |
планируется как можно чаще. |
QThread::InheritPriority |
7 |
используется тот же приоритет, что и у создающего потока. Это значение по умолчанию. |
Документация по функциям-членам
QThread::QThread(QObject *parent = nullptr)
Создает новый QThread для управления новым потоком. parent получает владение QThread. Поток не начинает выполнение до вызова start().
См. также start().
[private signal] void QThread::finished()
Этот сигнал испускается из связанного потока непосредственно перед завершением его выполнения.
При испускании этого сигнала цикл событий уже остановлен. Больше событий в потоке обрабатываться не будет, за исключением отложенных событий удаления. Этот сигнал может быть подключен к QObject::deleteLater(), чтобы освободить объекты в этом потоке.
Примечание: если связанный поток был завершен с помощью terminate(), неизвестно, из какого потока испускается этот сигнал.
Примечание: это частный сигнал. Он может использоваться в подключениях сигналов, но не может испускаться пользователем.
См. также started().
[slot] void QThread::quit()
Сообщает циклу событий потока о завершении с кодом возврата 0 (успех). Эквивалентно вызову QThread::exit(0).
Эта функция ничего не делает, если у потока нет цикла событий.
Примечание: эта функция является безопасной для потоков.
См. также exit() и QEventLoop.
[slot] void QThread::start(QThread::Priority priority = InheritPriority)
Начинает выполнение потока, вызвав run(). Операционная система запланирует поток в соответствии с параметром priority. Если поток уже запущен, эта функция ничего не делает.
Эффект параметра priority зависит от политики планирования операционной системы. В частности, priority будет проигнорирован на системах, которые не поддерживают приоритеты потоков (например, на Linux, см. документацию sched_setscheduler для получения дополнительных сведений).
См. также run() и terminate().
[private signal] void QThread::started()
Этот сигнал испускается из связанного потока при его запуске, перед вызовом функции run().
Примечание: это частный сигнал. Он может использоваться в подключениях сигналов, но не может испускаться пользователем.
См. также finished().
[slot] void QThread::terminate()
Прерывает выполнение потока. Поток может быть прерван немедленно или нет, в зависимости от политики планирования операционной системы. Используйте QThread::wait() после terminate(), чтобы быть уверенным.
Когда поток прерывается, все потоки, ожидающие завершения потока, будут разбужены.
Предупреждение: эта функция опасна, и ее использование не рекомендуется. Поток может быть прерван в любой точке его кода. Потоки могут быть прерваны во время изменения данных. У потока нет возможности очистить за собой, разблокировать любые захваченные мьютексы и т. д. Короче говоря, используйте эту функцию только в крайнем случае.
Прерывание может быть явно включено или отключено с помощью вызова QThread::setTerminationEnabled(). Вызов этой функции, когда прерывание отключено, приводит к отсрочке прерывания до повторного включения прерывания. См. документацию QThread::setTerminationEnabled() для получения дополнительной информации.
Примечание: эта функция является безопасной для потоков.
См. также setTerminationEnabled().
[virtual] QThread::~QThread()
Удаляет QThread.
Обратите внимание, что удаление объекта QThread не остановит выполнение управляемого им потока. Удаление работающего QThread (т. е. isFinished() возвращает false) приведет к сбою программы. Дождитесь сигнала finished() перед удалением QThread.
[static, since 5.10] template <typename Function, typename Args> QThread *QThread::create(Function &&f, Args &&... args)
Создает новый объект QThread, который будет выполнять функцию f с аргументами args.
Новый поток не запускается — его необходимо запустить с помощью явного вызова start(). Это позволяет подключаться к его сигналам, перемещать QObjects в поток, выбирать приоритет нового потока и т. д. Функция f будет вызвана в новом потоке.
Возвращает созданный экземпляр QThread.
Примечание: вызывающий получает владение возвращенным экземпляром QThread.
Предупреждение: не вызывайте start() для возвращенного экземпляра QThread более одного раза; в противном случае поведение будет неопределенным.
Эта функция была введена в Qt 5.10.
См. также start().
[static] QThread *QThread::currentThread()
Возвращает указатель на QThread, который управляет текущим потоком.
[static] Qt::HANDLE QThread::currentThreadId()
Возвращает дескриптор потока текущего выполняемого потока.
Предупреждение: дескриптор, возвращаемый этой функцией, используется для внутренних целей и не должен использоваться в каком-либо прикладном коде.
Примечание: в Windows эта функция возвращает DWORD (идентификатор потока Windows), возвращаемый функцией Win32 GetCurrentThreadId(), а не псевдо-HANDLE (дескриптор потока Windows), возвращаемый функцией Win32 GetCurrentThread().
[override virtual] bool QThread::event(QEvent *event)
Переопределяет: QObject::event(QEvent *e).
[since 5.0] QAbstractEventDispatcher *QThread::eventDispatcher() const
Возвращает указатель на объект диспетчера событий для потока. Если для потока диспетчера событий не существует, эта функция возвращает nullptr.
Эта функция была введена в Qt 5.0.
См. также setEventDispatcher().
[protected] int QThread::exec()
Входит в цикл обработки событий и ожидает, пока не будет вызвано exit(), возвращая значение, переданное в exit(). Возвращаемое значение равно 0, если exit() вызвано через quit().
Эта функция предназначена для вызова внутри run(). Необходимо вызвать эту функцию, чтобы начать обработку событий.
Примечание: Этот метод может быть вызван только внутри самого потока, т. е. когда это текущий поток.
void QThread::exit(int returnCode = 0)
Указывает циклу обработки событий потока завершиться с кодом возврата.
После вызова этой функции поток выходит из цикла обработки событий и возвращается из вызова QEventLoop::exec(). Функция QEventLoop::exec() возвращает returnCode.
Согласно соглашениям, returnCode со значением 0 означает успех, любое ненулевое значение указывает на ошибку.
Обратите внимание, что в отличие от функции C с тем же именем, эта функция действительно возвращается вызывающему методу — останавливается обработка событий.
Больше циклов QEventLoop не будут запускаться в этом потоке, пока не будет снова вызван QThread::exec(). Если цикл обработки событий в QThread::exec() не работает, следующий вызов QThread::exec() также вернётся немедленно.
Примечание: Эта функция безопасна для многопоточности.
См. также quit() и QEventLoop.
[static] int QThread::idealThreadCount()
Возвращает идеальное количество потоков, которое можно запустить в системе. Это выполняется путём запроса количества процессорных ядер, как физических, так и логических, в системе. Эта функция возвращает 1, если количество процессорных ядер не удалось определить.
bool QThread::isFinished() const
Возвращает true, если поток завершен; в противном случае возвращает false.
Примечание: Эта функция безопасна для многопоточности.
См. также isRunning().
[since 5.2] bool QThread::isInterruptionRequested() const
Возвращает true, если задачу, выполняемую в этом потоке, следует остановить. Запрос прерывания может быть выполнен с помощью requestInterruption().
Эта функция может использоваться для того, чтобы сделать задачи с длительным выполнением чисто прерываемыми. Никогда не проверяйте и не действуйте на основе возвращаемого этой функцией значения — это безопасно, однако рекомендуется периодически делать это в функциях с длительным выполнением. Будьте внимательны, чтобы не вызывать её слишком часто, чтобы сохранить низкую нагрузку.
void long_task() {
forever {
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
} Примечание: Этот метод может быть вызван только внутри самого потока, т. е. когда это текущий поток.
Функция была добавлена в Qt 5.2.
См. также currentThread() и requestInterruption().
bool QThread::isRunning() const
Возвращает true, если поток запущен; в противном случае возвращает false.
Примечание: Эта функция безопасна для многопоточности.
См. также isFinished().
[since 5.5] int QThread::loopLevel() const
Возвращает текущий уровень цикла обработки событий для потока.
Примечание: Этот метод может быть вызван только внутри самого потока, т. е. когда это текущий поток.
Функция была добавлена в Qt 5.5.
[static] void QThread::msleep(unsigned long msecs)
Заставляет текущий поток спать в течение msecs миллисекунд.
Избегайте использования этой функции, если вам нужно дождаться изменения заданного условия. Вместо этого подключите слот к сигналу, который указывает на изменение, или используйте обработчик событий (см. QObject::event()).
Примечание: Эта функция не гарантирует точности. При высокой нагрузке приложение может спать дольше, чем msecs. Некоторые операционные системы могут округлять msecs до 10 мс или 15 мс.
QThread::Priority QThread::priority() const
Возвращает приоритет выполняемого потока. Если поток не запущен, эта функция возвращает InheritPriority.
См. также Priority, setPriority() и start().
[since 5.2] void QThread::requestInterruption()
Запросить прерывание потока. Этот запрос рекомендательный, и код, выполняемый в потоке, сам решает, как и нужно ли реагировать на такой запрос. Эта функция не останавливает ни один работающий цикл обработки событий в потоке и не завершает его каким-либо образом.
Примечание: Эта функция безопасна для многопоточности.
Функция была добавлена в Qt 5.2.
См. также isInterruptionRequested().
[virtual protected] void QThread::run()
Точка входа для потока. После вызова start() новый поток вызывает эту функцию. По умолчанию она просто вызывает exec().
Вы можете переопределить эту функцию для управления потоками более сложным образом. Возврат из этого метода завершит выполнение потока.
[since 5.0] void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
Устанавливает диспетчер событий для потока в eventDispatcher. Это возможно только до тех пор, пока для потока ещё не установлен диспетчер событий. То есть, до запуска потока с помощью start() или, в случае основного потока, до создания QCoreApplication.
Этот метод принимает во владение объект.
Функция была добавлена в Qt 5.0.
См. также eventDispatcher().
void QThread::setPriority(QThread::Priority priority)
Эта функция устанавливает priority для работающего потока. Если поток не запущен, эта функция ничего не делает и возвращается сразу. Используйте start(), чтобы запустить поток с определённым приоритетом.
Аргумент priority может быть любым значением в перечислении QThread::Priority за исключением InheritPriority.
Эффект параметра priority зависит от политики планирования операционной системы. В частности, priority будет проигнорирован на системах, которые не поддерживают приоритеты потоков (например, на Linux, см. http://linux.die.net/man/2/sched_setscheduler для получения дополнительной информации).
См. также Priority, priority() и start().
void QThread::setStackSize(uint stackSize)
Устанавливает максимальный размер стека для потока в stackSize. Если stackSize больше нуля, максимальный размер стека устанавливается в stackSize байт, в противном случае максимальный размер стека определяется операционной системой автоматически.
Предупреждение: Большинство операционных систем устанавливают минимальные и максимальные ограничения на размеры стека потоков. Поток не сможет запуститься, если размер стека выходит за эти пределы.
См. также stackSize().
[static protected] void QThread::setTerminationEnabled(bool enabled = true)
Включает или отключает завершение текущего потока, в зависимости от параметра enabled. Поток должен быть запущен методом QThread.
Когда enabled false, завершение отключено. Будущие вызовы QThread::terminate() будут возвращать сразу без эффекта. Вместо этого завершение откладывается до включения.
Когда enabled true, завершение включено. Будущие вызовы QThread::terminate() обычно завершат поток. Если завершение было отложено (т. е. QThread::terminate() был вызван с отключённым завершением), эта функция завершит вызывающий поток немедленно. Обратите внимание, что эта функция в этом случае не вернётся.
См. также terminate().
[static] void QThread::sleep(unsigned long secs)
Заставляет текущий поток спать в течение secs секунд.
Избегайте использования этой функции, если вам нужно дождаться изменения заданного условия. Вместо этого подключите слот к сигналу, который указывает на изменение, или используйте обработчик событий (см. QObject::event()).
Примечание: Эта функция не гарантирует точности. При высокой нагрузке приложение может спать дольше, чем secs.
См. также msleep() и usleep().
uint QThread::stackSize() const
Возвращает максимальный размер стека для потока (если он был установлен с помощью setStackSize()); в противном случае возвращает ноль.
См. также setStackSize().
[static] void QThread::usleep(unsigned long usecs)
Заставляет текущий поток спать в течение usecs микросекунд.
Избегайте использования этой функции, если вам нужно дождаться изменения заданного условия. Вместо этого подключите слот к сигналу, указывающему на изменение, или используйте обработчик событий (см. QObject::event()).
Примечание: Эта функция не гарантирует точности. При большой нагрузке приложение может проспать больше, чем usecs. Некоторые операционные системы могут округлять usecs до 10 мс или 15 мс; в Windows оно будет округляться до кратного 1 мс.
[since 5.15] bool QThread::wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever))
Заблокирует поток до выполнения одного из следующих условий:
- Поток, связанный с объектом QThread, завершил выполнение (т.е. когда он возвращается из run()). Эта функция вернёт true, если поток завершился. Она также вернёт true, если поток ещё не запущен.
- Достигнут deadline. Эта функция вернёт false, если срок действия deadline истек.
Таймер deadline, установленный в QDeadlineTimer::Forever (по умолчанию), никогда не истечёт: в этом случае функция возвращается только тогда, когда поток возвращается из run() или если поток ещё не запущен.
Это обеспечивает функциональность, аналогичную функции POSIX pthread_join().
Эта функция была введена в Qt 5.15.
См. также sleep() и terminate().
bool QThread::wait(unsigned long time)
Это перегруженная функция.
[static] void QThread::yieldCurrentThread()
Уступает выполнение текущего потока другому выполнимому потоку, если таковой имеется. Обратите внимание, что операционная система решает, какому потоку переключиться.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/qthread.html