summaryrefslogtreecommitdiffstats
path: root/examples/thread
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-07-10 15:24:15 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-07-10 15:24:15 -0500
commitbd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch)
tree7a520322212d48ebcb9fbe1087e7fca28b76185c /examples/thread
downloadqt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz
qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip
Add Qt3 development HEAD version
Diffstat (limited to 'examples/thread')
-rw-r--r--examples/thread/prodcons/prodcons.cpp409
-rw-r--r--examples/thread/prodcons/prodcons.pro9
-rw-r--r--examples/thread/semaphores/main.cpp274
-rw-r--r--examples/thread/semaphores/semaphores.pro10
4 files changed, 702 insertions, 0 deletions
diff --git a/examples/thread/prodcons/prodcons.cpp b/examples/thread/prodcons/prodcons.cpp
new file mode 100644
index 0000000..bd13607
--- /dev/null
+++ b/examples/thread/prodcons/prodcons.cpp
@@ -0,0 +1,409 @@
+#include <qthread.h>
+#include <qwaitcondition.h>
+#include <qmutex.h>
+#include <qapplication.h>
+#include <qwidget.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qprogressbar.h>
+#include <qlayout.h>
+#include <qevent.h>
+#include <qlabel.h>
+#include <qcstring.h>
+#include <qtextstream.h>
+#include <qfile.h>
+
+#include <stdio.h>
+
+// 50kb buffer
+#define BUFSIZE (100*1000)
+#define PRGSTEP (BUFSIZE / 50)
+#define BLKSIZE (8)
+QByteArray bytearray;
+
+
+class ProdEvent : public QCustomEvent
+{
+public:
+ ProdEvent(long s, bool d)
+ : QCustomEvent(QEvent::User + 100), sz(s), dn(d)
+ { ; }
+
+ long size() const { return sz; }
+ bool done() const { return dn; }
+
+
+private:
+ long sz;
+ bool dn;
+};
+
+
+class ProdThread : public QThread
+{
+public:
+ ProdThread(QObject *r, QMutex *m, QWaitCondition *c);
+
+ void stop();
+ void run();
+
+
+private:
+ QObject *receiver;
+ QMutex *mutex;
+ QWaitCondition *condition;
+
+ bool done;
+};
+
+
+ProdThread::ProdThread(QObject *r, QMutex *m, QWaitCondition *c)
+ : receiver(r), mutex(m), condition(c), done(FALSE)
+{
+}
+
+
+void ProdThread::stop()
+{
+ mutex->lock();
+ done = TRUE;
+ mutex->unlock();
+}
+
+
+void ProdThread::run()
+{
+ bool stop = FALSE;
+ done = FALSE;
+
+ uchar *buffer = new uchar[BUFSIZE];
+ int pos = 0, oldpos = 0;
+ int loop = 1;
+ int lastpostedpos = 0;
+
+ ProdEvent *pe = new ProdEvent(pos, done);
+ QApplication::postEvent(receiver, pe);
+
+ while (! stop) {
+ oldpos = pos;
+ int i;
+ for (i = 0; i < BLKSIZE && pos < BUFSIZE; i++) {
+ buffer[pos++] = (loop % 2) ? 'o' : 'e';
+ }
+
+ mutex->lock();
+
+ if (pos == BUFSIZE) {
+ done = TRUE;
+ }
+
+ while (! bytearray.isNull() && ! stop) {
+ condition->wakeOne();
+ condition->wait(mutex);
+
+ stop = done;
+ }
+
+ stop = done;
+ bytearray.duplicate((const char *) (buffer + oldpos), pos - oldpos);
+ condition->wakeOne();
+
+ mutex->unlock();
+
+ if ( pos - lastpostedpos > PRGSTEP || stop ) {
+ lastpostedpos = pos;
+ ProdEvent *pe = new ProdEvent(pos, stop);
+ QApplication::postEvent(receiver, pe);
+ }
+
+ loop++;
+ }
+
+ condition->wakeOne();
+
+ delete [] buffer;
+}
+
+
+class ConsEvent : public QCustomEvent
+{
+public:
+ ConsEvent(long s)
+ : QCustomEvent(QEvent::User + 101), sz(s)
+ { ; }
+
+ long size() const { return sz; }
+
+
+private:
+ long sz;
+};
+
+
+class ConsThread : public QThread
+{
+public:
+ ConsThread(QObject *r, QMutex *m, QWaitCondition *c);
+
+ void stop();
+ void run();
+
+
+private:
+ QObject *receiver;
+ QMutex *mutex;
+ QWaitCondition *condition;
+
+ bool done;
+};
+
+
+ConsThread::ConsThread(QObject *r, QMutex *m, QWaitCondition *c)
+ : receiver(r), mutex(m), condition(c), done(FALSE)
+{
+}
+
+
+void ConsThread::stop()
+{
+ mutex->lock();
+ done = TRUE;
+ mutex->unlock();
+}
+
+
+void ConsThread::run()
+{
+ bool stop = FALSE;
+ done = FALSE;
+
+ QFile file("prodcons.out");
+ file.open(IO_WriteOnly);
+
+ long size = 0;
+ long lastsize = 0;
+
+ ConsEvent *ce = new ConsEvent(size);
+ QApplication::postEvent(receiver, ce);
+
+ while (! stop) {
+ mutex->lock();
+
+ while (bytearray.isNull() && ! stop) {
+ condition->wakeOne();
+ condition->wait(mutex);
+
+ stop = done;
+ }
+
+ if (size < BUFSIZE) {
+ file.writeBlock(bytearray.data(), bytearray.size());
+ size += bytearray.size();
+ bytearray.resize(0);
+ }
+
+ stop = done || size >= BUFSIZE;
+
+ mutex->unlock();
+
+ if ( size - lastsize > 1000 || stop ) {
+ lastsize = size;
+ ConsEvent *ce = new ConsEvent(size);
+ QApplication::postEvent(receiver, ce);
+ }
+ }
+
+ file.flush();
+ file.close();
+}
+
+
+class ProdCons : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ProdCons();
+ ~ProdCons();
+
+ void customEvent(QCustomEvent *);
+
+
+public slots:
+ void go();
+ void stop();
+
+
+private:
+ QMutex mutex;
+ QWaitCondition condition;
+
+ ProdThread *prod;
+ ConsThread *cons;
+
+ QPushButton *startbutton, *stopbutton;
+ QCheckBox *loopcheckbox;
+ QProgressBar *prodbar, *consbar;
+ bool stopped;
+ bool redraw;
+};
+
+
+ProdCons::ProdCons()
+ : QWidget(0, "producer consumer widget"),
+ prod(0), cons(0), stopped(FALSE), redraw(TRUE)
+{
+ startbutton = new QPushButton("&Start", this);
+ connect(startbutton, SIGNAL(clicked()), SLOT(go()));
+
+ stopbutton = new QPushButton("S&top", this);
+ connect(stopbutton, SIGNAL(clicked()), SLOT(stop()));
+ stopbutton->setEnabled(FALSE);
+
+ loopcheckbox = new QCheckBox("Loop", this);
+ loopcheckbox->setChecked(FALSE);
+
+ prodbar = new QProgressBar(BUFSIZE, this);
+ consbar = new QProgressBar(BUFSIZE, this);
+
+ QVBoxLayout *vbox = new QVBoxLayout(this, 8, 8);
+ vbox->addWidget(new QLabel(QString("Producer/Consumer using %1 byte buffer").
+ arg(BUFSIZE), this));
+ vbox->addWidget(startbutton);
+ vbox->addWidget(stopbutton);
+ vbox->addWidget(loopcheckbox);
+ vbox->addWidget(new QLabel("Producer progress:", this));
+ vbox->addWidget(prodbar);
+ vbox->addWidget(new QLabel("Consumer progress:", this));
+ vbox->addWidget(consbar);
+}
+
+
+ProdCons::~ProdCons()
+{
+ stop();
+
+ if (prod) {
+ delete prod;
+ prod = 0;
+ }
+
+ if (cons) {
+ delete cons;
+ cons = 0;
+ }
+}
+
+
+void ProdCons::go()
+{
+ stopped = FALSE;
+
+ mutex.lock();
+
+ if ( redraw ) {
+ startbutton->setEnabled(FALSE);
+ stopbutton->setEnabled(TRUE);
+ }
+
+ // start the consumer first
+ if (! cons)
+ cons = new ConsThread(this, &mutex, &condition);
+ cons->start();
+
+ // wait for consumer to signal that it has started
+ condition.wait(&mutex);
+
+ if (! prod)
+ prod = new ProdThread(this, &mutex, &condition);
+ prod->start();
+ mutex.unlock();
+}
+
+
+void ProdCons::stop()
+{
+ if (prod && prod->running()) {
+ prod->stop();
+ condition.wakeAll();
+ prod->wait();
+ }
+
+ if (cons && cons->running()) {
+ cons->stop();
+ condition.wakeAll();
+ cons->wait();
+ }
+
+ if ( redraw ) {
+ // no point in repainting these buttons so many times is we are looping...
+ startbutton->setEnabled(TRUE);
+ stopbutton->setEnabled(FALSE);
+ }
+
+ stopped = TRUE;
+}
+
+
+void ProdCons::customEvent(QCustomEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::User + 100:
+ {
+ // ProdEvent
+ ProdEvent *pe = (ProdEvent *) e;
+
+ if (pe->size() == 0 ||
+ pe->size() == BUFSIZE ||
+ pe->size() - prodbar->progress() >= PRGSTEP)
+ prodbar->setProgress(pe->size());
+
+ // reap the threads
+ if (pe->done()) {
+ bool loop = (loopcheckbox->isChecked() && ! stopped);
+ bool save_redraw = redraw;
+ redraw = !loop;
+
+ stop();
+
+ if (loop)
+ go();
+
+ redraw = save_redraw;
+ }
+
+ break;
+ }
+
+ case QEvent::User + 101:
+ {
+ // ConsEvent
+ ConsEvent *ce = (ConsEvent *) e;
+
+ if (ce->size() == 0 ||
+ ce->size() == BUFSIZE ||
+ ce->size() - consbar->progress() >= PRGSTEP)
+ consbar->setProgress(ce->size());
+
+ break;
+ }
+
+ default:
+ {
+ ;
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ ProdCons prodcons;
+ app.setMainWidget(&prodcons);
+ prodcons.show();
+ return app.exec();
+}
+
+
+#include "prodcons.moc"
diff --git a/examples/thread/prodcons/prodcons.pro b/examples/thread/prodcons/prodcons.pro
new file mode 100644
index 0000000..e728223
--- /dev/null
+++ b/examples/thread/prodcons/prodcons.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = prodcons
+
+CONFIG += qt warn_on
+
+REQUIRES = thread large-config
+
+SOURCES = prodcons.cpp
+CLEAN_FILES = prodcons.out
diff --git a/examples/thread/semaphores/main.cpp b/examples/thread/semaphores/main.cpp
new file mode 100644
index 0000000..d583c57
--- /dev/null
+++ b/examples/thread/semaphores/main.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of an example program for Qt. This example
+** program may be used, distributed and modified without limitation.
+**
+*****************************************************************************/
+#include <qapplication.h>
+#include <qwidget.h>
+#include <qpushbutton.h>
+#include <qmultilineedit.h>
+#include <qthread.h>
+#include <qsemaphore.h>
+#include <qmutex.h>
+#include <qlayout.h>
+#include <qmessagebox.h>
+#include <qlabel.h>
+
+#if defined(QT_NO_THREAD)
+# error Thread support not enabled.
+#endif
+
+// Use pointers to create semaphores after QApplication object!
+QSemaphore* yellowSem, *greenSem;
+
+
+class YellowThread : public QThread
+{
+public:
+ YellowThread(QWidget *o)
+ : receiver(o), stopped(FALSE)
+ { ; }
+
+ void run();
+ void stop();
+
+
+private:
+ QWidget *receiver;
+ QMutex mutex;
+ bool stopped;
+};
+
+
+void YellowThread::run()
+{
+ for (int i = 0; i < 20; i++) {
+ (*yellowSem)++;
+
+ QCustomEvent *event = new QCustomEvent(12345);
+ event->setData(new QString("Yellow!"));
+ QApplication::postEvent(receiver, event);
+ msleep(200);
+
+ (*greenSem)--;
+
+ mutex.lock();
+ if (stopped) {
+ stopped = FALSE;
+ mutex.unlock();
+ break;
+ }
+ mutex.unlock();
+ }
+
+ (*yellowSem)++;
+
+ QCustomEvent *event = new QCustomEvent(12346);
+ event->setData(new QString("Yellow!"));
+ QApplication::postEvent(receiver, event);
+
+ (*greenSem)--;
+}
+
+void YellowThread::stop()
+{
+ mutex.lock();
+ stopped = TRUE;
+ mutex.unlock();
+}
+
+
+class GreenThread: public QThread
+{
+public:
+ GreenThread(QWidget *o)
+ : receiver(o), stopped( FALSE )
+ { ; }
+
+ void run();
+ void stop();
+
+
+private:
+ QWidget *receiver;
+ QMutex mutex;
+ bool stopped;
+};
+
+
+void GreenThread::run()
+{
+ for (int i = 0; i < 20; i++) {
+ (*greenSem)++;
+
+ QCustomEvent *event = new QCustomEvent(12345);
+ event->setData(new QString("Green!"));
+ QApplication::postEvent(receiver, event);
+ msleep(200);
+
+ (*yellowSem)--;
+
+ mutex.lock();
+ if (stopped) {
+ stopped = FALSE;
+ mutex.unlock();
+ break;
+ }
+ mutex.unlock();
+ }
+
+ (*greenSem)++;
+
+ QCustomEvent *event = new QCustomEvent(12346);
+ event->setData(new QString("Green!"));
+ QApplication::postEvent(receiver, event);
+ msleep(10);
+
+ (*yellowSem)--;
+}
+
+void GreenThread::stop()
+{
+ mutex.lock();
+ stopped = TRUE;
+ mutex.unlock();
+}
+
+
+
+class SemaphoreExample : public QWidget
+{
+ Q_OBJECT
+public:
+ SemaphoreExample();
+ ~SemaphoreExample();
+
+ void customEvent(QCustomEvent *);
+
+
+public slots:
+ void startExample();
+
+
+protected:
+
+
+private:
+ QMultiLineEdit *mlineedit;
+ QPushButton *button;
+ QLabel *label;
+
+ YellowThread yellowThread;
+ GreenThread greenThread;
+};
+
+
+SemaphoreExample::SemaphoreExample()
+ : QWidget(), yellowThread(this), greenThread(this)
+{
+ yellowSem = new QSemaphore(1);
+ greenSem = new QSemaphore(1);
+
+ button = new QPushButton("&Ignition!", this);
+ connect(button, SIGNAL(clicked()), SLOT(startExample()));
+
+ mlineedit = new QMultiLineEdit(this);
+ label = new QLabel(this);
+
+ QVBoxLayout *vbox = new QVBoxLayout(this, 5);
+ vbox->addWidget(button);
+ vbox->addWidget(mlineedit);
+ vbox->addWidget(label);
+}
+
+
+SemaphoreExample::~SemaphoreExample()
+{
+ bool stopYellow = yellowThread.running(),
+ stopGreen = greenThread.running();
+ if (stopYellow)
+ yellowThread.stop();
+ if (greenThread.running())
+ greenThread.stop();
+ if (stopYellow)
+ yellowThread.wait();
+ if (stopGreen)
+ greenThread.wait();
+ delete yellowSem;
+ delete greenSem;
+}
+
+
+void SemaphoreExample::startExample()
+{
+ if (yellowThread.running() || greenThread.running()) {
+ QMessageBox::information(this, "Sorry",
+ "The threads have not completed yet, and must finish before "
+ "they can be started again.");
+
+ return;
+ }
+
+ mlineedit->clear();
+
+ while (yellowSem->available() < yellowSem->total()) (*yellowSem)--;
+ (*yellowSem)++;
+
+ yellowThread.start();
+ greenThread.start();
+}
+
+
+void SemaphoreExample::customEvent(QCustomEvent *event) {
+ switch (event->type()) {
+ case 12345:
+ {
+ QString *s = (QString *) event->data();
+
+ mlineedit->append(*s);
+
+ if (*s == "Green!")
+ label->setBackgroundColor(green);
+ else
+ label->setBackgroundColor(yellow);
+ label->setText(*s);
+
+ delete s;
+
+ break;
+ }
+
+ case 12346:
+ {
+ QString *s = (QString *) event->data();
+
+ QMessageBox::information(this, (*s) + " - Finished",
+ "The thread creating the \"" + *s +
+ "\" events has finished.");
+ delete s;
+
+ break;
+ }
+
+ default:
+ {
+ qWarning("Unknown custom event type: %d", event->type());
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ SemaphoreExample se;
+ app.setMainWidget(&se);
+ se.show();
+ return app.exec();
+}
+
+
+#include "main.moc"
diff --git a/examples/thread/semaphores/semaphores.pro b/examples/thread/semaphores/semaphores.pro
new file mode 100644
index 0000000..7804ce3
--- /dev/null
+++ b/examples/thread/semaphores/semaphores.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET = semaphores
+
+CONFIG += qt warn_on release thread
+
+REQUIRES = thread full-config
+
+HEADERS =
+SOURCES = main.cpp
+INTERFACES =