diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-12-06 18:29:37 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2012-12-06 18:29:37 -0600 |
commit | caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63 (patch) | |
tree | 860926c1e01068a8d3b8ea120630a48cf537424b | |
parent | 78125ea2f051107b84fdc0354acdedb7885308ee (diff) | |
download | qt3-caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63.tar.gz qt3-caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63.zip |
Add threading tutorial and fix a couple rare crashes
-rw-r--r-- | src/kernel/qapplication.cpp | 9 | ||||
-rw-r--r-- | src/kernel/qeventloop_unix.cpp | 2 | ||||
-rw-r--r-- | src/kernel/qeventloop_x11.cpp | 6 | ||||
-rw-r--r-- | tutorial/t15/main.cpp | 173 | ||||
-rw-r--r-- | tutorial/t15/main.h | 45 | ||||
-rw-r--r-- | tutorial/t15/t15.pro | 5 | ||||
-rw-r--r-- | tutorial/tutorial.pro | 2 |
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 |