Вызов `QQuickPaintedItem :: updateImage (const QImage & image)` безопасным для потока способом (без QThread) - PullRequest
0 голосов
/ 18 февраля 2020

Я читаю этот ответ о создании пользовательского QQuickPaintedItem в C ++ Как эффективно рисовать последовательное изображение в QQuickPaintedItem

, и я хочу написать код, который не является Qt -зависимая. То есть я не хочу полагаться на QThread. Я просто хочу позвонить CameraView::updateImage(const QImage& image) с std::thread, а не q QThread. Возможно ли это?

Я просто создал поток, передав ему экземпляр CameraView и вызвав его из потока. Однако это не потокобезопасно.

Как я могу вызвать CameraView::updateImage(const QImage& image) безопасным для потока способом?

1 Ответ

1 голос
/ 18 февраля 2020

Конечно, вы можете использовать классы стандартной библиотеки C ++ в своем коде. Например, используйте std::mutex для обновления изображения следующим образом:

void CameraView::updateImage(const QImage& image) {
    std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere
    // ... the rest of the code as before ...
}

Вы также можете оставить код CameraView без изменений и вызвать функцию updateImage из внешнего кода. Просто убедитесь, что изображение обновляется с использованием одного и того же мьютекса во всех потоках:

void functionInAnotherThread(CameraView& cameraView) {
    std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere

    // ... the rest of the code ...

    cameraView.updateImage(image);

    // ... the rest of the code ...
}

Давайте попробуем реализовать этот подход. Давайте немного изменим заголовочный файл:

class CameraView : public QQuickPaintedItem {
    Q_OBJECT
    Q_DISABLE_COPY(CameraView)

public:
    CameraView(QQuickItem* parent = nullptr);

public slots:
    void updateImage(const QImage&);
    void scheduleUpdate();

protected:
    QImage image_;
};

Теперь запишем определения методов:

void CameraView::updateImage(const QImage& image) {
    image_ = image.copy(); // Does deep copy of image data.
}

void CameraView::scheduleUpdate() {
    update();
}

void CameraView::paint(QPainter* painter) {
    painter->drawImage(this->boundingRect(), image_);
}

Наконец, мы напишем функцию обновления изображения и планирования перерисовки:

void functionInAnotherThread(CameraView& cameraView) {
    std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere

    cameraView.updateImage(image);

    lock.unlock(); // Unlock the mutex as we have already updated the image.

    QMetaObject::invokeMethod(&cameraView, "scheduleUpdate",
        Qt::QueuedConnection); // Call slot through the queued connection.
}

При Qt::QueuedConnection слот вызывается, когда управление возвращается к событию l oop потока получателя. Слот выполняется в потоке получателя. Таким образом, мы можем запланировать перерисовку виджета из другого потока. Попробуйте использовать другие типы соединений, если это не работает.

...