diff options
Diffstat (limited to 'examples/thread')
-rw-r--r-- | examples/thread/prodcons/prodcons.cpp | 409 | ||||
-rw-r--r-- | examples/thread/prodcons/prodcons.pro | 9 | ||||
-rw-r--r-- | examples/thread/semaphores/main.cpp | 274 | ||||
-rw-r--r-- | examples/thread/semaphores/semaphores.pro | 10 |
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 000000000..f6ff4500a --- /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) +TQByteArray bytearray; + + +class ProdEvent : public TQCustomEvent +{ +public: + ProdEvent(long s, bool d) + : TQCustomEvent(TQEvent::User + 100), sz(s), dn(d) + { ; } + + long size() const { return sz; } + bool done() const { return dn; } + + +private: + long sz; + bool dn; +}; + + +class ProdThread : public TQThread +{ +public: + ProdThread(TQObject *r, TQMutex *m, TQWaitCondition *c); + + void stop(); + void run(); + + +private: + TQObject *receiver; + TQMutex *mutex; + TQWaitCondition *condition; + + bool done; +}; + + +ProdThread::ProdThread(TQObject *r, TQMutex *m, TQWaitCondition *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); + TQApplication::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); + TQApplication::postEvent(receiver, pe); + } + + loop++; + } + + condition->wakeOne(); + + delete [] buffer; +} + + +class ConsEvent : public TQCustomEvent +{ +public: + ConsEvent(long s) + : TQCustomEvent(TQEvent::User + 101), sz(s) + { ; } + + long size() const { return sz; } + + +private: + long sz; +}; + + +class ConsThread : public TQThread +{ +public: + ConsThread(TQObject *r, TQMutex *m, TQWaitCondition *c); + + void stop(); + void run(); + + +private: + TQObject *receiver; + TQMutex *mutex; + TQWaitCondition *condition; + + bool done; +}; + + +ConsThread::ConsThread(TQObject *r, TQMutex *m, TQWaitCondition *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; + + TQFile file("prodcons.out"); + file.open(IO_WriteOnly); + + long size = 0; + long lastsize = 0; + + ConsEvent *ce = new ConsEvent(size); + TQApplication::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); + TQApplication::postEvent(receiver, ce); + } + } + + file.flush(); + file.close(); +} + + +class ProdCons : public TQWidget +{ + Q_OBJECT + +public: + ProdCons(); + ~ProdCons(); + + void customEvent(TQCustomEvent *); + + +public slots: + void go(); + void stop(); + + +private: + TQMutex mutex; + TQWaitCondition condition; + + ProdThread *prod; + ConsThread *cons; + + TQPushButton *startbutton, *stopbutton; + TQCheckBox *loopcheckbox; + TQProgressBar *prodbar, *consbar; + bool stopped; + bool redraw; +}; + + +ProdCons::ProdCons() + : TQWidget(0, "producer consumer widget"), + prod(0), cons(0), stopped(FALSE), redraw(TRUE) +{ + startbutton = new TQPushButton("&Start", this); + connect(startbutton, SIGNAL(clicked()), SLOT(go())); + + stopbutton = new TQPushButton("S&top", this); + connect(stopbutton, SIGNAL(clicked()), SLOT(stop())); + stopbutton->setEnabled(FALSE); + + loopcheckbox = new TQCheckBox("Loop", this); + loopcheckbox->setChecked(FALSE); + + prodbar = new TQProgressBar(BUFSIZE, this); + consbar = new TQProgressBar(BUFSIZE, this); + + TQVBoxLayout *vbox = new TQVBoxLayout(this, 8, 8); + vbox->addWidget(new TQLabel(TQString("Producer/Consumer using %1 byte buffer"). + arg(BUFSIZE), this)); + vbox->addWidget(startbutton); + vbox->addWidget(stopbutton); + vbox->addWidget(loopcheckbox); + vbox->addWidget(new TQLabel("Producer progress:", this)); + vbox->addWidget(prodbar); + vbox->addWidget(new TQLabel("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(TQCustomEvent *e) +{ + switch (e->type()) { + case TQEvent::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 TQEvent::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) +{ + TQApplication 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 000000000..e728223ea --- /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 000000000..69d4779d5 --- /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 TQt. 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 TQApplication object! +TQSemaphore* yellowSem, *greenSem; + + +class YellowThread : public TQThread +{ +public: + YellowThread(TQWidget *o) + : receiver(o), stopped(FALSE) + { ; } + + void run(); + void stop(); + + +private: + TQWidget *receiver; + TQMutex mutex; + bool stopped; +}; + + +void YellowThread::run() +{ + for (int i = 0; i < 20; i++) { + (*yellowSem)++; + + TQCustomEvent *event = new TQCustomEvent(12345); + event->setData(new TQString("Yellow!")); + TQApplication::postEvent(receiver, event); + msleep(200); + + (*greenSem)--; + + mutex.lock(); + if (stopped) { + stopped = FALSE; + mutex.unlock(); + break; + } + mutex.unlock(); + } + + (*yellowSem)++; + + TQCustomEvent *event = new TQCustomEvent(12346); + event->setData(new TQString("Yellow!")); + TQApplication::postEvent(receiver, event); + + (*greenSem)--; +} + +void YellowThread::stop() +{ + mutex.lock(); + stopped = TRUE; + mutex.unlock(); +} + + +class GreenThread: public TQThread +{ +public: + GreenThread(TQWidget *o) + : receiver(o), stopped( FALSE ) + { ; } + + void run(); + void stop(); + + +private: + TQWidget *receiver; + TQMutex mutex; + bool stopped; +}; + + +void GreenThread::run() +{ + for (int i = 0; i < 20; i++) { + (*greenSem)++; + + TQCustomEvent *event = new TQCustomEvent(12345); + event->setData(new TQString("Green!")); + TQApplication::postEvent(receiver, event); + msleep(200); + + (*yellowSem)--; + + mutex.lock(); + if (stopped) { + stopped = FALSE; + mutex.unlock(); + break; + } + mutex.unlock(); + } + + (*greenSem)++; + + TQCustomEvent *event = new TQCustomEvent(12346); + event->setData(new TQString("Green!")); + TQApplication::postEvent(receiver, event); + msleep(10); + + (*yellowSem)--; +} + +void GreenThread::stop() +{ + mutex.lock(); + stopped = TRUE; + mutex.unlock(); +} + + + +class SemaphoreExample : public TQWidget +{ + Q_OBJECT +public: + SemaphoreExample(); + ~SemaphoreExample(); + + void customEvent(TQCustomEvent *); + + +public slots: + void startExample(); + + +protected: + + +private: + TQMultiLineEdit *mlineedit; + TQPushButton *button; + TQLabel *label; + + YellowThread yellowThread; + GreenThread greenThread; +}; + + +SemaphoreExample::SemaphoreExample() + : TQWidget(), yellowThread(this), greenThread(this) +{ + yellowSem = new TQSemaphore(1); + greenSem = new TQSemaphore(1); + + button = new TQPushButton("&Ignition!", this); + connect(button, SIGNAL(clicked()), SLOT(startExample())); + + mlineedit = new TQMultiLineEdit(this); + label = new TQLabel(this); + + TQVBoxLayout *vbox = new TQVBoxLayout(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()) { + TQMessageBox::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(TQCustomEvent *event) { + switch (event->type()) { + case 12345: + { + TQString *s = (TQString *) event->data(); + + mlineedit->append(*s); + + if (*s == "Green!") + label->setBackgroundColor(green); + else + label->setBackgroundColor(yellow); + label->setText(*s); + + delete s; + + break; + } + + case 12346: + { + TQString *s = (TQString *) event->data(); + + TQMessageBox::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) +{ + TQApplication 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 000000000..7804ce341 --- /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 = |