Thread cleanup (still dodge) and fixed zoom too far in crash

This commit is contained in:
Mark Watkins 2011-09-05 12:30:10 +10:00
parent dcdb9549d4
commit 898f83c480
8 changed files with 129 additions and 89 deletions

View File

@ -138,10 +138,12 @@ void gBarChart::paint(gGraph & w,int left, int top, int width, int height)
quads->add(x1,py-h,col);
quads->add(x2,py-h,col2);
quads->add(x2,py,col2);
lines->add(x1,py,x1,py-h,blk);
lines->add(x1,py-h,x2,py-h,blk);
lines->add(x1,py,x2,py,blk);
lines->add(x2,py,x2,py-h,blk);
if (barw>2) {
lines->add(x1,py,x1,py-h,blk);
lines->add(x1,py-h,x2,py-h,blk);
lines->add(x1,py,x2,py,blk);
lines->add(x2,py,x2,py-h,blk);
}
py-=h;
}
}

View File

@ -73,7 +73,7 @@ void gFooBar::paint(gGraph & w,int left, int top, int width, int height)
w.qglColor(m_line_color);
glVertex2f(start_px, h);
glVertex2f(start_px+width, h);
glEnd(); */
glEnd();
double rmx=w.rmax_x-w.rmin_x;
double px=((1/rmx)*(w.min_x-w.rmin_x))*width;
@ -113,14 +113,14 @@ void gFooBar::paint(gGraph & w,int left, int top, int width, int height)
glVertex2f(start_px+px-extra,h);
glEnd();
/*glLineWidth(3);
glLineWidth(3);
glBegin(GL_LINES);
w.qglColor(m_handle_color);
glVertex2f(start_px+px-extra,h);
glVertex2f(start_px+py+extra,h);
glEnd(); */
glEnd();
glLineWidth(1);
glLineWidth(1); */
}

View File

@ -351,9 +351,9 @@ EventDataType LayerGroup::Maxy()
const double zoom_hard_limit=500.0;
gThread::gThread(gGraph *g)
gThread::gThread(gGraphView *g)
{
graph=g;
graphview=g;
mutex.lock();
}
gThread::~gThread()
@ -369,26 +369,25 @@ gThread::~gThread()
void gThread::run()
{
m_running=true;
gGraph * g;
while (m_running) {
graph->lockPaintMutex(); // will hang until in paintGL
// do nothing..
graph->unlockPaintMutex(); // unlock straight away
if (mutex.tryLock()) {
if (!m_running) break;
graph->paint(m_left,m_top,m_width,m_height);
graph->threadDone();
}
mutex.lock();
//mutex.unlock();
if (!m_running) break;
do {
g=graphview->popGraph();
if (g) {
g->paint(g->m_lastbounds.x(),g->m_lastbounds.y(),g->m_lastbounds.width(),g->m_lastbounds.height());
int i=0;
} else {
//mutex.lock();
graphview->masterlock->release(1); // This thread gives up for now..
}
} while (g);
}
}
void gThread::paint(int originX, int originY, int width, int height)
{
m_top=originY;
m_left=originX;
m_width=width;
m_height=height;
//wc.wakeAll();
mutex.unlock(); // this is the signal to start
}
gGraph::gGraph(gGraphView *graphview,QString title,int height,short group) :
m_graphview(graphview),
@ -413,16 +412,11 @@ gGraph::gGraph(gGraphView *graphview,QString title,int height,short group) :
m_quad=new GLBuffer(QColor(128,128,255,128),64,GL_QUADS);
m_quad->forceAntiAlias(true);
m_thread=new gThread(this);
}
gGraph::~gGraph()
{
delete m_thread;
delete m_quad;
}
void gGraph::lockPaintMutex() { m_graphview->inPaintMutex.lock(); }
void gGraph::unlockPaintMutex() { m_graphview->inPaintMutex.unlock(); }
bool gGraph::isEmpty()
{
@ -435,10 +429,6 @@ bool gGraph::isEmpty()
}
return empty;
}
void gGraph::threadDone()
{
m_graphview->masterlock->release(1);
}
void gGraph::drawGLBuf()
{
@ -578,7 +568,24 @@ void gGraph::paint(int originX, int originY, int width, int height)
quads()->add(originX+m_selection.x(),originY+top, originX+m_selection.x()+m_selection.width(),originY+top,col);
quads()->add(originX+m_selection.x()+m_selection.width(),originY+height-top-bottom, originX+m_selection.x(),originY+height-top-bottom,col);
}
}
void gGraphView::queGraph(gGraph * g,int left, int top, int width, int height)
{
g->m_lastbounds=QRect(left,top,width,height);
dl_mutex.lock();
m_drawlist.push_back(g);
dl_mutex.unlock();
}
gGraph * gGraphView::popGraph()
{
gGraph * g;
dl_mutex.lock();
if (!m_drawlist.isEmpty()) {
g=m_drawlist.at(0);
m_drawlist.pop_front();
} else g=NULL;
dl_mutex.unlock();
return g;
}
void gGraph::AddLayer(Layer * l,LayerPosition position, short width, short height, short order, bool movable, short x, short y)
@ -739,6 +746,7 @@ void gGraph::mouseReleaseEvent(QMouseEvent * event)
qint64 a1=MIN(j1,j2)
qint64 a2=MAX(j1,j2)
//if (a1<rmin_x) a1=rmin_x;
if (a2-a1<zoom_hard_limit) a2=a1+zoom_hard_limit;
if (a2>rmax_x) a2=rmax_x;
m_graphview->SetXBounds(a1,a2,m_group);
} else {
@ -748,6 +756,7 @@ void gGraph::mouseReleaseEvent(QMouseEvent * event)
qint64 j2=rmin_x+xmult*x2;
qint64 a1=MIN(j1,j2)
qint64 a2=MAX(j1,j2)
if (a2-a1<zoom_hard_limit) a2=a1+zoom_hard_limit;
//if (a1<rmin_x) a1=rmin_x;
if (a2>rmax_x) a2=rmax_x;
m_graphview->SetXBounds(a1,a2,m_group);
@ -1092,6 +1101,12 @@ gGraphView::gGraphView(QWidget *parent, gGraphView * shared) :
if (m_idealthreads<=0) m_idealthreads=1;
masterlock=new QSemaphore(m_idealthreads);
for (int i=0;i<m_idealthreads;i++) {
gThread * gt=new gThread(this);
m_threads.push_back(gt);
gt->start();
}
lines=new GLBuffer(QColor(0,0,0,0),100000,GL_LINES); // big fat shared line list
backlines=new GLBuffer(QColor(0,0,0,0),10000,GL_LINES); // big fat shared line list
quads=new GLBuffer(QColor(0,0,0,0),1024,GL_QUADS); // big fat shared line list
@ -1099,6 +1114,9 @@ gGraphView::gGraphView(QWidget *parent, gGraphView * shared) :
}
gGraphView::~gGraphView()
{
for (int i=0;i<m_threads.size();i++) {
delete m_threads[i];
}
for (int i=0;i<m_graphs.size();i++) {
delete m_graphs[i];
}
@ -1303,7 +1321,6 @@ void gGraphView::initializeGL()
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
inPaintMutex.lock();
}
void gGraphView::resizeGL(int w, int h)
@ -1323,10 +1340,6 @@ void gGraphView::paintGL()
if (width()<=0) return;
if (height()<=0) return;
inPaintMutex.unlock();
QTime time;
time.start();
glClearColor(255,255,255,255);
//glClearDepth(1);
@ -1357,8 +1370,12 @@ void gGraphView::paintGL()
// Tempory hack using this pref..
if (pref["EnableMultithreading"].toBool()) { // && (m_idealthreads>1)) {
threaded=true;
/*for (int i=0;i<m_idealthreads;i++) {
if (!m_threads[i]->isRunning())
m_threads[i]->start();
} */
} else threaded=false;
//threaded=false;
for (int i=0;i<m_graphs.size();i++) {
if (m_graphs[i]->isEmpty() || !m_graphs[i]->visible()) continue;
numgraphs++;
@ -1372,18 +1389,9 @@ void gGraphView::paintGL()
if ((py + h + graphSpacer) >= 0) {
w=width();
if (threaded) {
masterlock->acquire(1); // book an available CPU
//QFuture<void> future = QtConcurrent::run(m_graphs[i],&gGraph::paint,px,py,width()-titleWidth,h);
m_graphs[i]->threadStart(); // this only happens once.. It stays dormant when not in use.
m_graphs[i]->thread()->paint(px,py,width()-titleWidth,h);
//m_graphs[i]->thread()->setPriority(QThread::HighPriority);
} else {
m_graphs[i]->paint(px,py,width()-titleWidth,h);
}
queGraph(m_graphs[i],px,py,width()-titleWidth,h);
// draw the splitter handle
QColor ca=QColor(128,128,128,255);
backlines->add(0, py+h, w, py+h, ca);
ca=QColor(192,192,192,255);
@ -1394,24 +1402,38 @@ void gGraphView::paintGL()
}
py=ceil(py+h+graphSpacer);
}
//int thr=m_idealthreads;
QTime time;
time.start();
if (threaded) {
for (int i=0;i<m_idealthreads;i++) {
masterlock->acquire(1);
m_threads[i]->mutex.unlock();
}
// wait till all the threads are done
// ask for all the CPU's back..
masterlock->acquire(m_idealthreads);
masterlock->release(m_idealthreads);
} else { // just do it here
int s=m_drawlist.size();
for (int i=0;i<s;i++) {
gGraph *g=m_drawlist.at(0);
m_drawlist.pop_front();
g->paint(g->m_lastbounds.x(), g->m_lastbounds.y(), g->m_lastbounds.width(), g->m_lastbounds.height());
}
}
int elapsed=time.elapsed();
QColor col=Qt::black;
if (!numgraphs) {
int x,y;
GetTextExtent(m_emptytext,x,y,bigfont);
AddTextQue(m_emptytext,(width()/2)-x/2,(height()/2)+y/2,0.0,col,bigfont);
}
int thr;
if (threaded) {
thr=m_idealthreads;
// wait till all the threads are done
masterlock->acquire(m_idealthreads); // ask for all the CPU's back..
masterlock->release(m_idealthreads);
} else thr=1;
inPaintMutex.lock();
//((QGLContext*)context())->makeCurrent();
backlines->draw();
@ -1423,7 +1445,7 @@ void gGraphView::paintGL()
DrawTextQue();
if (pref["ShowDebug"].toBool()) {
QString ss;
ss="Draw took "+QString::number(time.elapsed())+"ms";
ss="PreDraw took "+QString::number(elapsed)+"ms";
AddTextQue(ss,width()-120,8,0,col,defaultfont);
DrawTextQue();
}

View File

@ -176,22 +176,19 @@ protected:
};
class gGraph;
class gThread:public QThread
{
public:
gThread(gGraph *g);
gThread(gGraphView *g);
~gThread();
void run();
void paint(int originX, int originY, int width, int height);
void die() { m_running=false; }
QMutex mutex;
protected:
gGraph * graph;
int m_top,m_left,m_width,m_height;
gGraphView *graphview;
volatile bool m_running;
QWaitCondition wc;
};
class gGraph
@ -253,20 +250,17 @@ public:
void setGroup(short group) { m_group=group; }
void DrawTextQue();
void setDay(Day * day);
gThread * thread() { return m_thread; }
virtual void paint(int originX, int originY, int width, int height);
void redraw();
void timedRedraw(int ms);
void threadDone();
bool threadRunning() { return m_thread->isRunning(); }
void threadStart() { if (!m_thread->isRunning()) m_thread->start(); }
GLBuffer * lines();
GLBuffer * backlines();
GLBuffer * quads();
short m_marginleft, m_marginright, m_margintop, m_marginbottom;
void lockPaintMutex();
void unlockPaintMutex();
QRect m_lastbounds;
protected:
//void invalidate();
@ -279,7 +273,6 @@ protected:
void ZoomX(double mult,int origin_px);
gThread * m_thread;
gGraphView * m_graphview;
QString m_title;
QVector<Layer *> m_layers;
@ -291,7 +284,6 @@ protected:
int m_max_height;
bool m_visible;
bool m_blockzoom;
QRect m_lastbounds;
QRect m_selection;
bool m_selecting_area;
QPoint m_current;
@ -343,11 +335,14 @@ public:
void setEmptyText(QString s) { m_emptytext=s; }
QMutex text_mutex;
QMutex gl_mutex;
QMutex inPaintMutex;
void setDay(Day * day);
QSemaphore * masterlock;
bool useThreads() { return m_idealthreads>1; }
GLBuffer * lines, * backlines, *quads;
gGraph * popGraph();
QVector<gThread *> m_threads;
protected:
int m_idealthreads;
Day * m_day;
@ -370,6 +365,10 @@ protected:
virtual void wheelEvent(QWheelEvent * event);
virtual void keyPressEvent(QKeyEvent * event);
void queGraph(gGraph *,int originX, int originY, int width, int height);
QMutex dl_mutex;
QList<gGraph *> m_drawlist;
gGraphView *m_shared; // convenient link to daily's graphs.
QVector<gGraph *> m_graphs;

View File

@ -87,8 +87,7 @@ void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int heigh
if (points->full()) { verts_exceeded=true; break; }
} else {
// thin lines down the bottom
lines->add(x1,start_py+1,m_flag_color);
lines->add(x1,start_py+1+12,m_flag_color);
lines->add(x1,start_py+1,x1,start_py+1+12,m_flag_color);
if (lines->full()) { verts_exceeded=true; break; }
}
@ -98,12 +97,10 @@ void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int heigh
z=top;
points->add(x1,top);
lines->add(x1,top,m_flag_color);
lines->add(x1,bottom,m_flag_color);
lines->add(x1,top,x1,bottom,m_flag_color);
if (points->full()) { verts_exceeded=true; break; }
} else {
lines->add(x1,z,m_flag_color);
lines->add(x1,z-12,m_flag_color);
lines->add(x1,z,x1,z-12,m_flag_color);
}
if (lines->full()) { verts_exceeded=true; break; }
if (xx<(1800000)) {

View File

@ -14,7 +14,7 @@ const quint64 divisors[]={
1800000,1200000,900000,600000,300000,120000,60000,45000,30000,
20000,15000,10000,5000,2000,1000,100,50,10
};
const int divcnt=sizeof(divisors)/sizeof(int);
const int divcnt=sizeof(divisors)/sizeof(quint64);
gXAxis::gXAxis(QColor col,bool fadeout)
:Layer(EmptyChannel)
@ -90,9 +90,10 @@ void gXAxis::paint(gGraph & w,int left,int top, int width, int height)
} else { // Microseconds
fd="00:00:00:000";
dividx=25;
divmax=divcnt;
divmax=divcnt-1;
fitmode=3;
}
//if (divmax>divcnt) divmax=divcnt;
int x,y;
GetTextExtent(fd,x,y);

View File

@ -23,9 +23,9 @@ MainWindow *mainwin=NULL;
void MyOutputHandler(QtMsgType type, const char *msg) {
if (!mainwin) {
return;
}
switch (type) {
case QtDebugMsg:
mainwin->Log(msg);
@ -42,6 +42,7 @@ void MyOutputHandler(QtMsgType type, const char *msg) {
// Popup a messagebox
//abort();
}
//loglock.unlock();
}
int main(int argc, char *argv[])

View File

@ -29,9 +29,27 @@ QStatusBar *qstatusbar;
void MainWindow::Log(QString s)
{
static QMutex loglock,strlock;
static int start=QDateTime::currentDateTime().toTime_t();
static QStringList slist;
if (!loglock.tryLock()) {
return;
}
strlock.lock();
QString tmp=QString("%1: %2").arg(QDateTime::currentDateTime().toTime_t()-start,5,10,QChar('0')).arg(s);
ui->logText->appendPlainText(tmp);
slist.append(tmp); //QStringList appears not to be threadsafe
strlock.unlock();
strlock.lock();
for (int i=0;i<slist.size();i++)
ui->logText->appendPlainText(slist[i]);
slist.clear();
strlock.unlock();
loglock.unlock();
}