TL; DR:

Я искал краткий пример потоковой передачи Qt, и все, что я нашел, было сложной "конфеткой", которая утверждала, что демонстрирует, как работают QThreads, но их было слишком много, чтобы понять.

Я принял ответ Дзена, потому что он показал мне именно то, чего не хватало в моих попытках, а затем добавил мою собственную в качестве примера, который я хотел увидеть. Нажмите здесь, чтобы перейти к нему: https://stackoverflow.com/a/34561122/3491308

Мой первоначальный вопрос следующий:


It seems I must be missing something, but I just can't seem to make this work like I think it ought to. My complete application needs to have two or three threads, all of which start (almost) together and run forever:

  • Графический интерфейс
    • Загружает группу объектов из файлов перед запуском двух других потоков для их обработки.
  • Процессор реального времени
    • Имеет TimeCriticalPriority и периодическое «прерывание» QTimer в попытке использовать ПК как гораздо более мощную встроенную систему, чем то, с чего я начал. Этот проект начинался как полностью встроенный и быстро стал слишком сложным, чтобы управлять им.
  • Драйвер USB HID
    • Подключается к части проекта, которая все еще встроена.

Основная функциональность, конечно же, связана с потоком обработки в реальном времени, а две другие - просто для настройки того, как это работает. Таким образом, объекты обработки создаются, изменяются и уничтожаются во время работы процессора реального времени на основе действий пользователя в графическом интерфейсе пользователя, и данные внутри некоторых из этих объектов также создаются и потребляются USB.

Я продолжаю искать примеры того, как использовать потоки в Qt, но все время получаю сложные приложения типа "леденец", которые загромождают потоки. Я изо всех сил пытаюсь интерпретировать их и писать свои собственные, но я продолжаю получать сбои в самой Qt, и мой небольшой проект "игровая площадка" говорит, что у меня даже нет второго потока:

#ifndef MAIN_H
#define MAIN_H

#include 

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow() {}
private:
    QObject* mythingy;
private slots:
    void deleteObject(QObject* thingy);
};

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker(QObject* thingy, QObject* parent = 0);
private:
    QObject* mythingy;
signals:
    void deleteObject(QObject* thingy);
private slots:
    void doWork();
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include 

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    Worker* worker = new Worker(mythingy, this);
    connect(worker, SIGNAL(deleteObject(QObject*)), this, SLOT(deleteObject(QObject*)));
}

void MainWindow::deleteObject(QObject* thingy)
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    delete thingy;
}



Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(parent)
{
    mythingy = thingy;
    QThread* thread = new QThread(this);
    this->moveToThread(thread);

    //use a timer to allow the constructor to exit
    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    thread->start();
}

void Worker::doWork()
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    deleteObject(mythingy);
}

Если кто-то может опубликовать пример того, как правильно выполнять QThreads, учитывая мое описание проекта и с минимальным беспорядком (желательно короче моего, если это возможно), я был бы очень признателен.


Изменить:

Судя по ответу Дзена, похоже, это тоже работает:

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    Worker* worker = new Worker(mythingy, this);
}

Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(0)    //no real parent, so we can move to a different thread
{
    mythingy = thingy;

    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

    QThread* thread = new QThread(parent);
    this->moveToThread(thread);
    thread->start();
}

void Worker::doWork()
{
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    delete mythingy;
}

Я все еще перемещаюсь внутри конструктора и удаляю объект напрямую, вместо того, чтобы указывать потоку владельца сделать это. (помните, что в полном проекте владелец уже пометил объект для удаления, но воздержался от этого, потому что другой поток мог его использовать)

Что-то не так?

AaronD

Ответов: 2

Ответы (2)

1. вы не можете перемещать объекты с родителем. Поэтому вместо Worker * worker = new Worker (mythingy, this);вы должны использовать Worker * worker = new Worker (mythingy);
2. вы не можете создавать потомков для родителя, который находится в другом потоке.

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    QThread* thisthread = this->thread();
    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
    //*****************
    Worker* worker = new Worker(mythingy);
    QThread* thread = new QThread();
    worker->moveToThread(thread);
    thread->start();
    //*****************
    connect(worker, SIGNAL(deleteObject(QObject*)), this, SLOT(deleteObject(QObject*)));
}

Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(parent)
{
    mythingy = thingy;
//    QThread* thread = new QThread(this);
//    this->moveToThread(thread);

    //use a timer to allow the constructor to exit
    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);
    timer->start(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(doWork()));

//    QThread* thisthread = this->thread();
//    QThread* mainthread = QCoreApplication::instance()->thread();
    //breakpoint here to check thisthread and mainthread
//    thread->start();
}

Слоты объекта всегда выполняются потоком, в котором он живет. Итак, поскольку вы никогда не перемещали MainWindow, нет необходимости проверять его поток в MainWindow :: deleteObject. Например:

Worker* worker = new Worker(mythingy);
QThread* thread = new QThread();
worker->moveToThread(thread);
thread->start();

//wrong: directly invoking doWork in mainthread    
worker->doWork();

//correct: through signal-slot mechanics
connect(this, SIGNAL(startWork()), worker, SLOT(doWork()));

Вот краткий пример, который я искал с помощью Дзен. Он хорошо умещается (по крайней мере, на моем экране), если вы прокрутите его до конца. Заголовочный файл сверху нужен просто для его компиляции.

#ifndef MAIN_H
#define MAIN_H

#include 

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker(QObject* thingy, QObject* parent = 0);
private:
    QObject* mythingy;
private slots:
    void doWork();
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow();
private:
    QObject* mythingy;
    Worker* myworker;
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include 

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    mythingy = new QObject(this);
    myworker = new Worker(mythingy, this);
}

MainWindow::~MainWindow()
{
    delete myworker;
}

Worker::Worker(QObject* thingy, QObject* parent)
    : QObject(0)    //no real parent, so we can move to a different thread
{
    mythingy = thingy;

    //move myself to a new thread and start it
    QThread* thread = new QThread(parent);
    connect(thread, SIGNAL(started()), this, SLOT(doWork()));
    this->moveToThread(thread);
    thread->start();
}

void Worker::doWork()
{
    //deleting an object from a different thread:
    //requires careful planning to make it safe, but seems to work as expected
    delete mythingy;
}

Комментарии указывают на важные части, а остальное, опять же, просто для того, чтобы он вообще работал. Вы можете добавить это в doWork (), чтобы убедиться, что это другой поток:

QThread* thisthread = this->thread();
QThread* mainthread = QCoreApplication::instance()->thread();

Установите точку останова сразу после этого и убедитесь, что указатели другие.


• 100001

2022 WebDevInsider