summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-12-06 18:29:37 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-12-06 18:29:37 -0600
commitcaf80d88243aaa00e8f1baeaa6b7e4c3aca75f63 (patch)
tree860926c1e01068a8d3b8ea120630a48cf537424b
parent78125ea2f051107b84fdc0354acdedb7885308ee (diff)
downloadqt3-caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63.tar.gz
qt3-caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63.zip
Add threading tutorial and fix a couple rare crashes
-rw-r--r--src/kernel/qapplication.cpp9
-rw-r--r--src/kernel/qeventloop_unix.cpp2
-rw-r--r--src/kernel/qeventloop_x11.cpp6
-rw-r--r--tutorial/t15/main.cpp173
-rw-r--r--tutorial/t15/main.h45
-rw-r--r--tutorial/t15/t15.pro5
-rw-r--r--tutorial/tutorial.pro2
7 files changed, 237 insertions, 5 deletions
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp
index a9c9fb8..f3b0119 100644
--- a/src/kernel/qapplication.cpp
+++ b/src/kernel/qapplication.cpp
@@ -2767,7 +2767,10 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e)
if (!handled) {
#if defined(QT_THREAD_SUPPORT)
- bool locked = QApplication::qt_mutex->locked();
+ bool locked = false;
+ if (QApplication::qt_mutex) {
+ locked = QApplication::qt_mutex->locked();
+ }
if (locked) {
QApplication::qt_mutex->unlock();
}
@@ -2775,7 +2778,9 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e)
consumed = receiver->event( e );
#if defined(QT_THREAD_SUPPORT)
if (locked) {
- QApplication::qt_mutex->lock();
+ if (QApplication::qt_mutex) {
+ QApplication::qt_mutex->lock();
+ }
}
#endif
}
diff --git a/src/kernel/qeventloop_unix.cpp b/src/kernel/qeventloop_unix.cpp
index 202ef12..80c8f29 100644
--- a/src/kernel/qeventloop_unix.cpp
+++ b/src/kernel/qeventloop_unix.cpp
@@ -562,6 +562,8 @@ int QEventLoop::activateTimers()
n_act++;
QTimerEvent e( t->id );
QApplication::sendEvent( t->obj, &e ); // send event
+ if ( !timerList ) // sendEvent allows other threads to execute, therefore we must check for list existence when it returns!
+ return 0;
if ( timerList->findRef( begin ) == -1 )
begin = 0;
}
diff --git a/src/kernel/qeventloop_x11.cpp b/src/kernel/qeventloop_x11.cpp
index cd3e865..5ee41ca 100644
--- a/src/kernel/qeventloop_x11.cpp
+++ b/src/kernel/qeventloop_x11.cpp
@@ -284,7 +284,8 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
// unlock the GUI mutex and select. when we return from this function, there is
// something for us to do
#if defined(QT_THREAD_SUPPORT)
- locker.mutex()->unlock();
+ if ( locker.mutex() ) locker.mutex()->unlock();
+ else return false;
#endif
int nsel;
@@ -298,7 +299,8 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
// relock the GUI mutex before processing any pending events
#if defined(QT_THREAD_SUPPORT)
- locker.mutex()->lock();
+ if ( locker.mutex() ) locker.mutex()->lock();
+ else return false;
#endif
// we are awake, broadcast it
diff --git a/tutorial/t15/main.cpp b/tutorial/t15/main.cpp
new file mode 100644
index 0000000..4c96083
--- /dev/null
+++ b/tutorial/t15/main.cpp
@@ -0,0 +1,173 @@
+/****************************************************************
+**
+** Qt threading tutorial
+** (c) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
+**
+** This tutorial is released into the Public Domain and
+** can therefore be modified and/or used for any purpose
+**
+****************************************************************/
+
+#include "main.h"
+
+#include <unistd.h>
+
+#include <qtimer.h>
+#include <qeventloop.h>
+
+void WorkerObject::run()
+{
+ qDebug( "[%s] thread: %p event loop: %p", threadFriendlyName.ascii(), QThread::currentThreadObject(), QApplication::eventLoop() );
+
+ QEventLoop* eventLoop = QApplication::eventLoop();
+ if (!eventLoop) return;
+
+ QTimer *t = new QTimer(this);
+ connect( t, SIGNAL(timeout()), SLOT(timerHandler()) );
+ t->start( 1000, FALSE );
+
+ for( int count = 0; count < 5; count++ ) {
+ sleep( 1 );
+ qDebug( "[%s] Ping!", threadFriendlyName.ascii() );
+ displayMessage("Hi", "There!");
+ eventLoop->processEvents(QEventLoop::AllEvents);
+ }
+
+ eventLoop->exit(0);
+}
+
+void WorkerObject::timerHandler()
+{
+ qDebug( "[%s] Timer fired!", threadFriendlyName.ascii() );
+}
+
+void MainObject::emitMessage(QString str1, QString str2)
+{
+ qDebug( "%s", ("[MainObject] emitMessage: " + str1 + " " + str2).ascii() );
+}
+
+void MainObject::buttonClicked()
+{
+ qDebug( "[MainObject] Button clicked!" );
+
+ QEventLoop* eventLoop = QApplication::eventLoop();
+ if (!eventLoop) return;
+ eventLoop->exit(0);
+}
+
+#define SET_UP_WORKER(x, y, z) \
+ WorkerObject x; \
+ x.threadFriendlyName = y; \
+ x.moveToThread(&z); \
+ QObject::connect(&x, SIGNAL(displayMessage(QString,QString)), &mainobject, SLOT(emitMessage(QString,QString))); \
+ QTimer::singleShot(0, &x, SLOT(run()));
+
+int main( int argc, char **argv )
+{
+ QApplication a( argc, argv );
+
+ qDebug( "[MainObject] thread: %p event loop: %p", QThread::currentThreadObject(), QApplication::eventLoop() );
+
+ QPushButton hello( "Exit", 0 );
+ hello.resize( 100, 30 );
+
+ MainObject mainobject;
+
+ QEventLoopThread workerthread0;
+ QEventLoopThread workerthread1;
+ QEventLoopThread workerthread2;
+ QEventLoopThread workerthread3;
+ QEventLoopThread workerthread4;
+ QEventLoopThread workerthread5;
+ QEventLoopThread workerthread6;
+ QEventLoopThread workerthread7;
+ QEventLoopThread workerthread8;
+ QEventLoopThread workerthread9;
+
+ QEventLoopThread workerthread10;
+ QEventLoopThread workerthread11;
+ QEventLoopThread workerthread12;
+ QEventLoopThread workerthread13;
+ QEventLoopThread workerthread14;
+ QEventLoopThread workerthread15;
+ QEventLoopThread workerthread16;
+ QEventLoopThread workerthread17;
+ QEventLoopThread workerthread18;
+ QEventLoopThread workerthread19;
+
+ SET_UP_WORKER(workerobject0, "WorkerObject0", workerthread0)
+ SET_UP_WORKER(workerobject1, "WorkerObject1", workerthread1)
+ SET_UP_WORKER(workerobject2, "WorkerObject2", workerthread2)
+ SET_UP_WORKER(workerobject3, "WorkerObject3", workerthread3)
+ SET_UP_WORKER(workerobject4, "WorkerObject4", workerthread4)
+ SET_UP_WORKER(workerobject5, "WorkerObject5", workerthread5)
+ SET_UP_WORKER(workerobject6, "WorkerObject6", workerthread6)
+ SET_UP_WORKER(workerobject7, "WorkerObject7", workerthread7)
+ SET_UP_WORKER(workerobject8, "WorkerObject8", workerthread8)
+ SET_UP_WORKER(workerobject9, "WorkerObject9", workerthread9)
+
+ SET_UP_WORKER(workerobject10, "WorkerObjec10", workerthread10)
+ SET_UP_WORKER(workerobject11, "WorkerObjec11", workerthread11)
+ SET_UP_WORKER(workerobject12, "WorkerObjec12", workerthread12)
+ SET_UP_WORKER(workerobject13, "WorkerObjec13", workerthread13)
+ SET_UP_WORKER(workerobject14, "WorkerObjec14", workerthread14)
+ SET_UP_WORKER(workerobject15, "WorkerObjec15", workerthread15)
+ SET_UP_WORKER(workerobject16, "WorkerObjec16", workerthread16)
+ SET_UP_WORKER(workerobject17, "WorkerObjec17", workerthread17)
+ SET_UP_WORKER(workerobject18, "WorkerObjec18", workerthread18)
+ SET_UP_WORKER(workerobject19, "WorkerObjec19", workerthread19)
+
+ workerthread0.start();
+ workerthread1.start();
+ workerthread2.start();
+ workerthread3.start();
+ workerthread4.start();
+ workerthread5.start();
+ workerthread6.start();
+ workerthread7.start();
+ workerthread8.start();
+ workerthread9.start();
+
+ workerthread10.start();
+ workerthread11.start();
+ workerthread12.start();
+ workerthread13.start();
+ workerthread14.start();
+ workerthread15.start();
+ workerthread16.start();
+ workerthread17.start();
+ workerthread18.start();
+ workerthread19.start();
+
+ a.setMainWidget( &hello );
+ QObject::connect(&hello, SIGNAL(clicked()), &mainobject, SLOT(buttonClicked()));
+ hello.show();
+ a.exec();
+ hello.hide();
+
+ qDebug( "[MainObject] Waiting for thread completion..." );
+
+ workerthread0.wait();
+ workerthread1.wait();
+ workerthread2.wait();
+ workerthread3.wait();
+ workerthread4.wait();
+ workerthread5.wait();
+ workerthread6.wait();
+ workerthread7.wait();
+ workerthread8.wait();
+ workerthread9.wait();
+
+ workerthread10.wait();
+ workerthread11.wait();
+ workerthread12.wait();
+ workerthread13.wait();
+ workerthread14.wait();
+ workerthread15.wait();
+ workerthread16.wait();
+ workerthread17.wait();
+ workerthread18.wait();
+ workerthread19.wait();
+
+ qDebug( "[MainObject] Finished!" );
+}
diff --git a/tutorial/t15/main.h b/tutorial/t15/main.h
new file mode 100644
index 0000000..13ac5df
--- /dev/null
+++ b/tutorial/t15/main.h
@@ -0,0 +1,45 @@
+/****************************************************************
+**
+** Qt threading tutorial
+** (c) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
+**
+** This tutorial is released into the Public Domain and
+** can therefore be modified and/or used for any purpose
+**
+****************************************************************/
+
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+#include <qapplication.h>
+#include <qobject.h>
+#include <qpushbutton.h>
+#include <qthread.h>
+
+class MainObject;
+
+class WorkerObject : public QObject
+{
+ Q_OBJECT
+
+ public slots:
+ void run();
+ void timerHandler();
+
+ signals:
+ void displayMessage(QString, QString);
+
+ public:
+ QString threadFriendlyName;
+};
+
+class MainObject : public QObject
+{
+ Q_OBJECT
+
+ public slots:
+ void emitMessage(QString, QString);
+ void buttonClicked();
+};
+
+#endif // _MAIN_H_
diff --git a/tutorial/t15/t15.pro b/tutorial/t15/t15.pro
new file mode 100644
index 0000000..ff0f08d
--- /dev/null
+++ b/tutorial/t15/t15.pro
@@ -0,0 +1,5 @@
+TEMPLATE = app
+CONFIG += qt warn_on release
+HEADERS = main.h
+SOURCES = main.cpp
+TARGET = t15
diff --git a/tutorial/tutorial.pro b/tutorial/tutorial.pro
index 32b31d7..90e37f7 100644
--- a/tutorial/tutorial.pro
+++ b/tutorial/tutorial.pro
@@ -1,2 +1,2 @@
TEMPLATE = subdirs
-SUBDIRS = t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14
+SUBDIRS = t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15