BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Qt5 Tutorial QThreads and QSemaphore for Producer and Consumer - 2020





Bookmark and Share





bogotobogo.com site search:




QThreads and QSemaphore for Producer and Consumer

In this tutorial, we will learn how we can use QSemaphore for Producer and Consumer.

This Semaphores tutorial will show how to use QSemaphore to control access to a circular buffer shared by a producer thread and a consumer thread.

Your browser does not support the video tag.

Video recording - Producer and Consumer model using QSemaphore


The producer writes data to the buffer until it reaches the end of the buffer, at which point it restarts from the beginning, overwriting existing data. The consumer thread reads the data as it is produced and writes it to standard error.

Semaphores make it possible to have a higher level of concurrency than mutexes. If accesses to the buffer were guarded by a QMutex, the consumer thread couldn't access the buffer at the same time as the producer thread. Yet, there is no harm in having both threads working on different parts of the buffer at the same time.
- from http://qt-project.org/doc/qt-5.0/qtcore/semaphores.html

The example comprises mainly three classes: Producer, Consumer, and the QDialog class. Both inherit from QThread. The circular buffer used for communicating between these two classes and the semaphores that protect it are global variables.

QSemaFileList.png



Global Variables

The use of semaphores ensure that the producer is never more than BufferSize bytes ahead of the consumer, and that the consumer never reads data that the producer hasn't generated yet. In other words, we use QSemaphore to control access to a circular buffer shared by a producer thread and a consumer thread.

To achieve the goal, we use global variables:

const int DataSize = 100000;

const int BufferSize = 8192;
char buffer[BufferSize];

QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;

DataSize is the amout of data that the producer will generate. To keep the example as simple as possible, we make it a constant. BufferSize is the size of the circular buffer. It is less than DataSize, meaning that at some point the producer will reach the end of the buffer and restart from the beginning.

To synchronize the producer and the consumer, we need two semaphores. The freeBytes semaphore controls the "free" area of the buffer (the area that the producer hasn't filled with data yet or that the consumer has already read). The usedBytes semaphore controls the "used" area of the buffer (the area that the producer has filled but that the consumer hasn't read yet).

The freeBytes semaphore is initialized with BufferSize, because initially the entire buffer is empty. The usedBytes semaphore is initialized to 0 (the default value if none is specified).





Producer Class

Producer class looks like this:

// producer.cpp

#include "producer.h"
#include "common.h"

Producer::Producer(QObject *parent) :
    QThread(parent)
{
}

void Producer::run()
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    for (int i = 0; i < DataSize; ++i) {
        freeBytes.acquire();
        buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
        usedBytes.release();
        if(i % 20 == 0)
        emit bufferFillCountChanged(usedBytes.available());
        emit producerCountChanged(i);
    }
}

The producer generates DataSize bytes of data. Before it writes a byte to the circular buffer, it must acquire a "free" byte using the freeBytes semaphore. The QSemaphore::acquire() call might block if the consumer hasn't kept up the pace with the producer.

At the end, the producer releases a byte using the usedBytes semaphore. The "free" byte has successfully been transformed into a "used" byte, ready to be read by the consumer.

The usedBytes.available() is for UI purpose. It returns the available bytes for consumer.

This class emits two signals: one for the number of bytes produced so far, and the level of bytes available to consume.





Consumer Class

The code is almost symmetric to the Producer class, except that this time we acquire a "used" byte and release a "free" byte, instead of the opposite.

// consumer.cpp

#include "consumer.h"
#include "common.h"

Consumer::Consumer(QObject *parent) :
    QThread(parent)
{
}

void Consumer::run()
{
    for (int i = 0; i < DataSize; ++i) {
        usedBytes.acquire();
        fprintf(stderr, "%c", buffer[i % BufferSize]);
        freeBytes.release();
        emit bufferFillCountChanged(usedBytes.available());
        emit consumerCountChanged(i);
    }
    fprintf(stderr, "\n");
}




Dialog Class

When the program fires up QDialog, two new QThreads are created in the constructor. Then, when the Start button is clicked, the two threads call start().

// conproddialog.cpp

#include "conproddialog.h"
#include "ui_conproddialog.h"
#include "myConstants.h"

// BufferSize: maximum bytes that can be stored
char buffer[BufferSize];

QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;

ConProdDialog::ConProdDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ConProdDialog)
{
    ui->setupUi(this);

    // progress bar range setup
    ui->producerProgressBar->setRange(0, DataSize);
    ui->consumerProgressBar->setRange(0, DataSize);
    ui->bufferProgressBar->setRange(0, BufferSize);

    // make two threads
    mProducer = new Producer(this);
    mConsumer = new Consumer(this);

    // connect signal/slot for the buffer progress bar
    connect(mConsumer, SIGNAL(bufferFillCountChanged(int)),
              this, SLOT(onBufferValueChanged(int)));
    connect(mProducer, SIGNAL(bufferFillCountChanged(int)),
              this, SLOT(onBufferValueChanged(int)));

    // connect signal/slot for consumer/producer progress bar
    connect(mConsumer, SIGNAL(consumerCountChanged(int)),
              this, SLOT(onConsumerValueChanged(int)));
    connect(mProducer, SIGNAL(producerCountChanged(int)),
              this, SLOT(onProducerValueChanged(int)));
}

ConProdDialog::~ConProdDialog()
{
    delete ui;
}

void ConProdDialog::onBufferValueChanged(int bCount)
{
    ui->bufferProgressBar->setValue(bCount);
}

void ConProdDialog::onProducerValueChanged(int pCount)
{
    ui->producerProgressBar->setValue(pCount);
}

void ConProdDialog::onConsumerValueChanged(int cCount)
{
    ui->consumerProgressBar->setValue(cCount);
}

// start button clicked
void ConProdDialog::on_startButton_clicked()
{
    // disable the start button
    ui->startButton->setEnabled(false);

    // threads starat
    mProducer->start();
    mConsumer->start();
}

The UI looks like this:

QSemaphoreUI.png



Source Files

Here is the source file: ConProd2.zip.


Here are the other code not shown in this page:

main.cpp:

#include "conproddialog.h"
#include <QApplication>
#include "conproddialog.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ConProdDialog w;
    w.setWindowTitle("Semaphore: Consumer & Producer");
    w.show();

    return a.exec();
}

common.h:

#ifndef COMMON_H
#define COMMON_H

#include <QSemaphore>
#include "myConstants.h"

extern char buffer[BufferSize];

extern QSemaphore freeBytes;
extern QSemaphore usedBytes;

#endif // COMMON_H

myConstants.h:

#ifndef MYCONSTANTS_H
#define MYCONSTANTS_H
const int DataSize = 100000;
const int BufferSize = 8192;
#endif // MYCONSTANTS_H

conproddialog.h:

#ifndef CONPRODDIALOG_H
#define CONPRODDIALOG_H

#include <QDialog>
#include "consumer.h"
#include "producer.h"

#include <QSemaphore>


namespace Ui {
class ConProdDialog;
}

class ConProdDialog : public QDialog
{
    Q_OBJECT

public:
    explicit ConProdDialog(QWidget *parent = 0);
    ~ConProdDialog();

public slots:
    void onBufferValueChanged(int);
    void onProducerValueChanged(int);
    void onConsumerValueChanged(int);

private slots:
    void on_startButton_clicked();

private:
    Ui::ConProdDialog *ui;
    Producer *mProducer;
    Consumer *mConsumer;
};

#endif // CONPRODDIALOG_H

producer.h:

#ifndef PRODUCER_H
#define PRODUCER_H

#include <QThread>
#include <QTime>

class Producer : public QThread
{
    Q_OBJECT
public:
    explicit Producer(QObject *parent = 0);
    void run();

signals:
    void bufferFillCountChanged(int bCount);
    void producerCountChanged(int count);

public slots:
};

#endif // PRODUCER_H

consumer.h:

#ifndef CONSUMER_H
#define CONSUMER_H

#include <QThread>
#include <QTime>


class Consumer : public QThread
{
    Q_OBJECT
public:
    explicit Consumer(QObject *parent = 0);
    void run();

signals:
    //void stringConsumed(const QString &text;);
    void bufferFillCountChanged(int cCount);
    void consumerCountChanged(int count);
public slots:
};

#endif // CONSUMER_H

And finally, .pro:

ConProd2.pro:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = ConProd2
TEMPLATE = app


SOURCES += main.cpp\
        conproddialog.cpp \
    consumer.cpp \
    producer.cpp

HEADERS  += conproddialog.h \
    consumer.h \
    producer.h \
    common.h \
    myConstants.h

FORMS    += conproddialog.ui




Run - Screen shot and video recording

QSema_ScreenShot.png

Your browser does not support the video tag.





Qt 5 Tutorial

  1. Hello World
  2. Signals and Slots
  3. Q_OBJECT Macro
  4. MainWindow and Action
  5. MainWindow and ImageViewer using Designer A
  6. MainWindow and ImageViewer using Designer B
  7. Layouts
  8. Layouts without Designer
  9. Grid Layouts
  10. Splitter
  11. QDir
  12. QFile (Basic)
  13. Resource Files (.qrc)
  14. QComboBox
  15. QListWidget
  16. QTreeWidget
  17. QAction and Icon Resources
  18. QStatusBar
  19. QMessageBox
  20. QTimer
  21. QList
  22. QListIterator
  23. QMutableListIterator
  24. QLinkedList
  25. QMap
  26. QHash
  27. QStringList
  28. QTextStream
  29. QMimeType and QMimeDatabase
  30. QFile (Serialization I)
  31. QFile (Serialization II - Class)
  32. Tool Tips in HTML Style and with Resource Images
  33. QPainter
  34. QBrush and QRect
  35. QPainterPath and QPolygon
  36. QPen and Cap Style
  37. QBrush and QGradient
  38. QPainter and Transformations
  39. QGraphicsView and QGraphicsScene
  40. Customizing Items by inheriting QGraphicsItem
  41. QGraphicsView Animation
  42. FFmpeg Converter using QProcess
  43. QProgress Dialog - Modal and Modeless
  44. QVariant and QMetaType
  45. QtXML - Writing to a file
  46. QtXML - QtXML DOM Reading
  47. QThreads - Introduction
  48. QThreads - Creating Threads
  49. Creating QThreads using QtConcurrent
  50. QThreads - Priority
  51. QThreads - QMutex
  52. QThreads - GuiThread
  53. QtConcurrent QProgressDialog with QFutureWatcher
  54. QSemaphores - Producer and Consumer
  55. QThreads - wait()
  56. MVC - ModelView with QListView and QStringListModel
  57. MVC - ModelView with QTreeView and QDirModel
  58. MVC - ModelView with QTreeView and QFileSystemModel
  59. MVC - ModelView with QTableView and QItemDelegate
  60. QHttp - Downloading Files
  61. QNetworkAccessManager and QNetworkRequest - Downloading Files
  62. Qt's Network Download Example - Reconstructed
  63. QNetworkAccessManager - Downloading Files with UI and QProgressDialog
  64. QUdpSocket
  65. QTcpSocket
  66. QTcpSocket with Signals and Slots
  67. QTcpServer - Client and Server
  68. QTcpServer - Loopback Dialog
  69. QTcpServer - Client and Server using MultiThreading
  70. QTcpServer - Client and Server using QThreadPool
  71. Asynchronous QTcpServer - Client and Server using QThreadPool
  72. Qt Quick2 QML Animation - A
  73. Qt Quick2 QML Animation - B
  74. Short note on Ubuntu Install
  75. OpenGL with QT5
  76. Qt5 Webkit : Web Browser with QtCreator using QWebView Part A
  77. Qt5 Webkit : Web Browser with QtCreator using QWebView Part B
  78. Video Player with HTML5 QWebView and FFmpeg Converter
  79. Qt5 Add-in and Visual Studio 2012
  80. Qt5.3 Installation on Ubuntu 14.04
  81. Qt5.5 Installation on Ubuntu 14.04
  82. Short note on deploying to Windows







Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong






Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Qt 5 Tutorial



Hello World

Signals and Slots

Q_OBJECT Macro

MainWindow and Action

MainWindow and ImageViewer using Designer A

MainWindow and ImageViewer using Designer B

Layouts

Layouts without Designer

Grid Layouts

Splitter

QDir

QFile (Basic)

Resource Files (.qrc)

QComboBox

QListWidget

QTreeWidget

QAction and Icon Resources

QStatusBar

QMessageBox

QTimer

QList

QListIterator

QMutableListIterator

QLinkedList

QMap

QHash

QStringList

QTextStream

QMimeType and QMimeDatabase

QFile (Serialization I)

QFile (Serialization II - Class)

Tool Tips in HTML Style and with Resource Images

QPainter

QBrush and QRect

QPainterPath and QPolygon

QPen and Cap Style

QBrush and QGradient

QPainter and Transformations

QGraphicsView and QGraphicsScene

Customizing Items by inheriting QGraphicsItem

QGraphicsView Animation

FFmpeg Converter using QProcess

QProgress Dialog - Modal and Modeless

QVariant and QMetaType

QtXML - Writing to a file

QtXML - QtXML DOM Reading

QThreads - Introduction

QThreads - Creating Threads

Creating QThreads using QtConcurrent

QThreads - Priority

QThreads - QMutex

QThreads - GuiThread

QtConcurrent QProgressDialog with QFutureWatcher

QSemaphores - Producer and Consumer

QThreads - wait()

MVC - ModelView with QListView and QStringListModel

MVC - ModelView with QTreeView and QDirModel

MVC - ModelView with QTreeView and QFileSystemModel

MVC - ModelView with QTableView and QItemDelegate

QHttp - Downloading Files

QNetworkAccessManager and QNetworkRequest - Downloading Files

Qt's Network Download Example - Reconstructed

QNetworkAccessManager - Downloading Files with UI and QProgressDialog

QUdpSocket

QTcpSocket

QTcpSocket with Signals and Slots

QTcpServer - Client and Server

QTcpServer - Loopback Dialog

QTcpServer - Client and Server using MultiThreading

QTcpServer - Client and Server using QThreadPool

Asynchronous QTcpServer - Client and Server using QThreadPool

Qt Quick2 QML Animation - A

Qt Quick2 QML Animation - B

Short note on Ubuntu Install

OpenGL with QT5

Qt5 Webkit : Web Browser with QtCreator using QWebView Part A

Qt5 Webkit : Web Browser with QtCreator using QWebView Part B

Video Player with HTML5 QWebView and FFmpeg Converter

Qt5 Add-in and Visual Studio 2012

Qt5.3 Installation on Ubuntu 14.04

Qt5.5 Installation on Ubuntu 14.04

Short note on deploying to Windows




Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong













Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master