I'm trying to draw a Mandelbrot set in QT. All is done and it's looking good, but it need some time to calculate the color of pixel, so i wanted to split picture in 4 and give calculation to separated threads. Threads are working and the problem is: after math i want to generate object (my Pixel structure) and pass it to the queque with enqueue() method, which from my paintEvent getting x,y and color to draw. Adding to the queue generates:
18:09:15: The program has unexpectedly finished.
18:09:15: The process was ended forcefully.
without it, threads are working normally
method Plot::get_iterations_from_thread() in 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();
}
using it:
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 && 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;
}
}
}
and the 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
by the way: the emit function is commented because it doesn't work and i don't know really why, which frustrate me a lot