You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
410 lines
7.0 KiB
410 lines
7.0 KiB
#include <ntqthread.h>
|
|
#include <ntqwaitcondition.h>
|
|
#include <ntqmutex.h>
|
|
#include <ntqapplication.h>
|
|
#include <ntqwidget.h>
|
|
#include <ntqpushbutton.h>
|
|
#include <ntqcheckbox.h>
|
|
#include <ntqprogressbar.h>
|
|
#include <ntqlayout.h>
|
|
#include <ntqevent.h>
|
|
#include <ntqlabel.h>
|
|
#include <ntqcstring.h>
|
|
#include <ntqtextstream.h>
|
|
#include <ntqfile.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
|
|
{
|
|
TQ_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"
|