#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 вычисления выполняются быстрее, но я ни хрена не вижу