добавление в QQueue приводит к сбою программы

#c #qt #queue #thread-safety #mandelbrot

#c #qt #очередь #потокобезопасность #мандельброт

Вопрос:

Я пытаюсь нарисовать набор Мандельброта в QT. Все сделано, и выглядит хорошо, но для вычисления цвета пикселя требуется некоторое время, поэтому я хотел разделить изображение на 4 и передать вычисления отдельным потокам. Потоки работают, и проблема в следующем: после вычисления я хочу сгенерировать объект (мою пиксельную структуру) и передать его в queque с помощью метода enqueue (), который из моего paintEvent получает x, y и цвет для рисования. Добавление в очередь генерирует:

 18:09:15: The program has unexpectedly finished.
18:09:15: The process was ended forcefully.
  

без этого потоки работают нормально

построение метода::get_iterations_from_thread() в Plot.cpp

 #include "plot.h"


QMutex Plot::mutex;

Plot::Plot(QWidget *parent) : QWidget(parent)
{ 
    connect(this,
            SIGNAL(get_iterations(unsigned int, unsigned int, int, int)),
            this,
            SLOT(get_iterations_from_thread(unsigned int, unsigned int, int, int)),
            Qt::ConnectionType::QueuedConnection);

    th1.set_values(0, (width/2)-1,
                   0, (height/2)-1,
                   cxmin, cxmax, cymin, cymax,
                   max_check, "TH1");
    std::cout << th1.name   " values setted" << std::endl;

    th2.set_values((width/2) 1, width,
                   0, (height/2)-1,
                   cxmin, cxmax, cymin, cymax,
                   max_check, "TH2");
    std::cout << th2.name   " values setted" << std::endl;

    th3.set_values(0, (width/2)-1,
                   (height/2) 1, height,
                   cxmin, cxmax, cymin, cymax,
                   max_check, "TH3");
    std::cout << th3.name   " values setted" << std::endl;

    th4.set_values((width/2) 1, width,
                   (height/2) 1, height,
                   cxmin, cxmax, cymin, cymax,
                   max_check, "TH4");
    std::cout << th4.name   " values setted" << std::endl;

    th1.start();
    th2.start();
    th3.start();
    th4.start();
}

void Plot::get_iterations_from_thread(unsigned int iterations, unsigned int max_check, int x,  int y)
{
    mutex.lock();
    std::cout << "generating pixel" << std::endl;
    Pixel pix(x, y, iterations, max_check);
    pixels.enqueue(pix);
    std::cout << "pixel generated!" << std::endl;
    mutex.unlock();
}

void Plot::paintEvent(QPaintEvent *e)
{
    std::cout << "paintEvent" << std::endl;
    mutex.lock();
    QPainter painter;
    painter.begin(this);
    QPen pen(Qt::white);
    pen.setWidth(1);
    pen.setCapStyle(Qt::SquareCap);
    if(!pixels.isEmpty()){
        foreach(Pixel pixel, pixels){
            std::cout << "painting "   std::to_string(pixel.get_x())   ","   std::to_string(pixel.get_y()) << std::endl;
            pen.setColor(pixel.get_color());
            painter.setPen(pen);
            painter.drawPoint(pixel.get_x(), pixel.get_y());
            pixels.dequeue();
        }
    }
    painter.end();

    mutex.unlock();

}
  

используя его:

 void CountingThread::run()
{
    Plot * window = dynamic_cast<Plot*>(parent());
    for(int x=x_start; x<x_stop;   x){
        for(int y=y_start; y<y_stop;   y){

            std::complex<double> c(cxmin   x/(width-1.5)*(cxmax-cxmin), cymin   y/(height-0.5)*(cymax-cymin));
            std::complex<double> z(0,0);
            unsigned int iterations;
            for (iterations = 0; iterations < max_check amp;amp; std::abs(z) < 2.0;   iterations) {
                z = z*z   c;
            }

            std::cout << name   " done for: "   std::to_string(x)   ","   std::to_string(y)   " " << std::endl;
            //emit(window->get_iterations(iterations, max_check, x, y));
            window->get_iterations_from_thread(iterations, max_check, x, y);
            std::cout << name   " emitted" << std::endl;
        }
    }

}
  

и Plot.h

 #ifndef PLOT_H
#define PLOT_H

#include <QWidget>
#include <QPainter>

#include <iostream>

#include "countingthread.h"
#include "pixel.h"

class Plot : public QWidget
{
    Q_OBJECT
public:
    explicit Plot(QWidget *parent = nullptr);
    static QMutex mutex;
    QQueue<Pixel> pixels;

private:
    void Plot::paintEvent(QPaintEvent *e) override;
    CountingThread th1;
    CountingThread th2;
    CountingThread th3;
    CountingThread th4;

    int width = 820;
    int height = 640;
    double cxmin = -1.5;
    double cxmax = 0.5;
    double cymin = -1.0;
    double cymax = 1.0;
    unsigned int max_check = 100;

signals:
    void get_iterations(unsigned int iterations, unsigned int max_check, int x,  int y);

public slots:
    void get_iterations_from_thread(unsigned int iterations, unsigned int max_check, int x,  int y);
};

#endif // PLOT_H

  

кстати: функция emit прокомментирована, потому что она не работает, и я действительно не знаю почему, что меня очень расстраивает

Комментарии:

1. Я советую не помещать всю эту логику времени выполнения внутрь конструктора ( Plot::Plot ). Конструкторы IMO должны быть скудными и выполнять минимальную работу по созданию объекта.

2. Теперь это быстрее из-за разделения изображения на 4?

3. @MediaEU вычисления выполняются быстрее, но я ни хрена не вижу