source: trunk/examples/thread/prodcons/prodcons.cpp@ 25

Last change on this file since 25 was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 7.3 KB
Line 
1#include <qthread.h>
2#include <qwaitcondition.h>
3#include <qmutex.h>
4#include <qapplication.h>
5#include <qwidget.h>
6#include <qpushbutton.h>
7#include <qcheckbox.h>
8#include <qprogressbar.h>
9#include <qlayout.h>
10#include <qevent.h>
11#include <qlabel.h>
12#include <qcstring.h>
13#include <qtextstream.h>
14#include <qfile.h>
15
16#include <stdio.h>
17
18// 50kb buffer
19#define BUFSIZE (100*1000)
20#define PRGSTEP (BUFSIZE / 50)
21#define BLKSIZE (8)
22QByteArray bytearray;
23
24
25class ProdEvent : public QCustomEvent
26{
27public:
28 ProdEvent(long s, bool d)
29 : QCustomEvent(QEvent::User + 100), sz(s), dn(d)
30 { ; }
31
32 long size() const { return sz; }
33 bool done() const { return dn; }
34
35
36private:
37 long sz;
38 bool dn;
39};
40
41
42class ProdThread : public QThread
43{
44public:
45 ProdThread(QObject *r, QMutex *m, QWaitCondition *c);
46
47 void stop();
48 void run();
49
50
51private:
52 QObject *receiver;
53 QMutex *mutex;
54 QWaitCondition *condition;
55
56 bool done;
57};
58
59
60ProdThread::ProdThread(QObject *r, QMutex *m, QWaitCondition *c)
61 : receiver(r), mutex(m), condition(c), done(FALSE)
62{
63}
64
65
66void ProdThread::stop()
67{
68 mutex->lock();
69 done = TRUE;
70 mutex->unlock();
71}
72
73
74void ProdThread::run()
75{
76 bool stop = FALSE;
77 done = FALSE;
78
79 uchar *buffer = new uchar[BUFSIZE];
80 int pos = 0, oldpos = 0;
81 int loop = 1;
82 int lastpostedpos = 0;
83
84 ProdEvent *pe = new ProdEvent(pos, done);
85 QApplication::postEvent(receiver, pe);
86
87 while (! stop) {
88 oldpos = pos;
89 int i;
90 for (i = 0; i < BLKSIZE && pos < BUFSIZE; i++) {
91 buffer[pos++] = (loop % 2) ? 'o' : 'e';
92 }
93
94 mutex->lock();
95
96 if (pos == BUFSIZE) {
97 done = TRUE;
98 }
99
100 while (! bytearray.isNull() && ! stop) {
101 condition->wakeOne();
102 condition->wait(mutex);
103
104 stop = done;
105 }
106
107 stop = done;
108 bytearray.duplicate((const char *) (buffer + oldpos), pos - oldpos);
109 condition->wakeOne();
110
111 mutex->unlock();
112
113 if ( pos - lastpostedpos > PRGSTEP || stop ) {
114 lastpostedpos = pos;
115 ProdEvent *pe = new ProdEvent(pos, stop);
116 QApplication::postEvent(receiver, pe);
117 }
118
119 loop++;
120 }
121
122 condition->wakeOne();
123
124 delete [] buffer;
125}
126
127
128class ConsEvent : public QCustomEvent
129{
130public:
131 ConsEvent(long s)
132 : QCustomEvent(QEvent::User + 101), sz(s)
133 { ; }
134
135 long size() const { return sz; }
136
137
138private:
139 long sz;
140};
141
142
143class ConsThread : public QThread
144{
145public:
146 ConsThread(QObject *r, QMutex *m, QWaitCondition *c);
147
148 void stop();
149 void run();
150
151
152private:
153 QObject *receiver;
154 QMutex *mutex;
155 QWaitCondition *condition;
156
157 bool done;
158};
159
160
161ConsThread::ConsThread(QObject *r, QMutex *m, QWaitCondition *c)
162 : receiver(r), mutex(m), condition(c), done(FALSE)
163{
164}
165
166
167void ConsThread::stop()
168{
169 mutex->lock();
170 done = TRUE;
171 mutex->unlock();
172}
173
174
175void ConsThread::run()
176{
177 bool stop = FALSE;
178 done = FALSE;
179
180 QFile file("prodcons.out");
181 file.open(IO_WriteOnly);
182
183 long size = 0;
184 long lastsize = 0;
185
186 ConsEvent *ce = new ConsEvent(size);
187 QApplication::postEvent(receiver, ce);
188
189 while (! stop) {
190 mutex->lock();
191
192 while (bytearray.isNull() && ! stop) {
193 condition->wakeOne();
194 condition->wait(mutex);
195
196 stop = done;
197 }
198
199 if (size < BUFSIZE) {
200 file.writeBlock(bytearray.data(), bytearray.size());
201 size += bytearray.size();
202 bytearray.resize(0);
203 }
204
205 stop = done || size >= BUFSIZE;
206
207 mutex->unlock();
208
209 if ( size - lastsize > 1000 || stop ) {
210 lastsize = size;
211 ConsEvent *ce = new ConsEvent(size);
212 QApplication::postEvent(receiver, ce);
213 }
214 }
215
216 file.flush();
217 file.close();
218}
219
220
221class ProdCons : public QWidget
222{
223 Q_OBJECT
224
225public:
226 ProdCons();
227 ~ProdCons();
228
229 void customEvent(QCustomEvent *);
230
231
232public slots:
233 void go();
234 void stop();
235
236
237private:
238 QMutex mutex;
239 QWaitCondition condition;
240
241 ProdThread *prod;
242 ConsThread *cons;
243
244 QPushButton *startbutton, *stopbutton;
245 QCheckBox *loopcheckbox;
246 QProgressBar *prodbar, *consbar;
247 bool stopped;
248 bool redraw;
249};
250
251
252ProdCons::ProdCons()
253 : QWidget(0, "producer consumer widget"),
254 prod(0), cons(0), stopped(FALSE), redraw(TRUE)
255{
256 startbutton = new QPushButton("&Start", this);
257 connect(startbutton, SIGNAL(clicked()), SLOT(go()));
258
259 stopbutton = new QPushButton("S&top", this);
260 connect(stopbutton, SIGNAL(clicked()), SLOT(stop()));
261 stopbutton->setEnabled(FALSE);
262
263 loopcheckbox = new QCheckBox("Loop", this);
264 loopcheckbox->setChecked(FALSE);
265
266 prodbar = new QProgressBar(BUFSIZE, this);
267 consbar = new QProgressBar(BUFSIZE, this);
268
269 QVBoxLayout *vbox = new QVBoxLayout(this, 8, 8);
270 vbox->addWidget(new QLabel(QString("Producer/Consumer using %1 byte buffer").
271 arg(BUFSIZE), this));
272 vbox->addWidget(startbutton);
273 vbox->addWidget(stopbutton);
274 vbox->addWidget(loopcheckbox);
275 vbox->addWidget(new QLabel("Producer progress:", this));
276 vbox->addWidget(prodbar);
277 vbox->addWidget(new QLabel("Consumer progress:", this));
278 vbox->addWidget(consbar);
279}
280
281
282ProdCons::~ProdCons()
283{
284 stop();
285
286 if (prod) {
287 delete prod;
288 prod = 0;
289 }
290
291 if (cons) {
292 delete cons;
293 cons = 0;
294 }
295}
296
297
298void ProdCons::go()
299{
300 stopped = FALSE;
301
302 mutex.lock();
303
304 if ( redraw ) {
305 startbutton->setEnabled(FALSE);
306 stopbutton->setEnabled(TRUE);
307 }
308
309 // start the consumer first
310 if (! cons)
311 cons = new ConsThread(this, &mutex, &condition);
312 cons->start();
313
314 // wait for consumer to signal that it has started
315 condition.wait(&mutex);
316
317 if (! prod)
318 prod = new ProdThread(this, &mutex, &condition);
319 prod->start();
320 mutex.unlock();
321}
322
323
324void ProdCons::stop()
325{
326 if (prod && prod->running()) {
327 prod->stop();
328 condition.wakeAll();
329 prod->wait();
330 }
331
332 if (cons && cons->running()) {
333 cons->stop();
334 condition.wakeAll();
335 cons->wait();
336 }
337
338 if ( redraw ) {
339 // no point in repainting these buttons so many times is we are looping...
340 startbutton->setEnabled(TRUE);
341 stopbutton->setEnabled(FALSE);
342 }
343
344 stopped = TRUE;
345}
346
347
348void ProdCons::customEvent(QCustomEvent *e)
349{
350 switch (e->type()) {
351 case QEvent::User + 100:
352 {
353 // ProdEvent
354 ProdEvent *pe = (ProdEvent *) e;
355
356 if (pe->size() == 0 ||
357 pe->size() == BUFSIZE ||
358 pe->size() - prodbar->progress() >= PRGSTEP)
359 prodbar->setProgress(pe->size());
360
361 // reap the threads
362 if (pe->done()) {
363 bool loop = (loopcheckbox->isChecked() && ! stopped);
364 bool save_redraw = redraw;
365 redraw = !loop;
366
367 stop();
368
369 if (loop)
370 go();
371
372 redraw = save_redraw;
373 }
374
375 break;
376 }
377
378 case QEvent::User + 101:
379 {
380 // ConsEvent
381 ConsEvent *ce = (ConsEvent *) e;
382
383 if (ce->size() == 0 ||
384 ce->size() == BUFSIZE ||
385 ce->size() - consbar->progress() >= PRGSTEP)
386 consbar->setProgress(ce->size());
387
388 break;
389 }
390
391 default:
392 {
393 ;
394 }
395 }
396}
397
398
399int main(int argc, char **argv)
400{
401 QApplication app(argc, argv);
402 ProdCons prodcons;
403 app.setMainWidget(&prodcons);
404 prodcons.show();
405 return app.exec();
406}
407
408
409#include "prodcons.moc"
Note: See TracBrowser for help on using the repository browser.