Fix prod con example

This commit is contained in:
Robin Dietzel 2023-12-02 16:04:12 +01:00
parent 5e7049feb0
commit fa11a8d942
17 changed files with 161 additions and 348 deletions

View File

@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.14)
project(BarlasChpt3Ex12 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
add_executable(BarlasChpt3Ex12
main.cpp
)
target_link_libraries(BarlasChpt3Ex12 Qt${QT_VERSION_MAJOR}::Core)
include(GNUInstallDirs)
install(TARGETS BarlasChpt3Ex12
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@ -1,86 +0,0 @@
#include <iostream>
#include <QSemaphore>
#include <QThread>
/*
* Barlas Chpt 3 Ex 12:
Create three threads, each printing out the letters A, B, and C.
The printing must adhere to these rules:
The total number of Bs and Cs that have been output at any
point in the output string cannot exceed the total number
of As that have been output at that point.
After a C has been output, another C cannot be output until
one or more Bs have been output.
Use semaphores to solve the problem.
*/
class printer{
private:
QSemaphore* lockBC;
QSemaphore* lockC;
public:
printer(QSemaphore* lockBC, QSemaphore* lockC){
this->lockBC = lockBC;
this->lockC = lockC;
}
void printA(){
this->lockBC->release(1);
std::cout << "A\n";
}
void printB(){
if(this->lockBC->tryAcquire(1)){
if(this->lockC->available() == 0){
this->lockC->release(1);
}
std::cout << "B\n";
}
}
void printC(){
if(this->lockBC->tryAcquire(1)){
if(this->lockC->tryAcquire(1)){
std::cout << "C\n";
}else{
this->lockBC->release(1);
}
}
}
};
class worker : public QThread{
private:
QSemaphore* lockBC;
QSemaphore* lockC;
public:
worker(QSemaphore* lockBC, QSemaphore* lockC){
this->lockBC = lockBC;
this->lockC = lockC;
}
void run(){
printer print = printer(this->lockBC, this->lockC);
print.printA();
print.printB();
print.printC();
}
};
int main(int argc, char *argv[])
{
QSemaphore lockC(1);
QSemaphore lockBC(0);
int N = 3;
worker *workers[N];
for(int i = 0; i < N; i++){
workers[i] = new worker(&lockBC, &lockC);
workers[i]->run();
}
return 0;
}

View File

@ -26,4 +26,5 @@ add_subdirectory(third-party/fmt)
# Include CMakeLists files from subdirs for specific tasks
add_subdirectory(task1)
add_subdirectory(task3)
add_subdirectory(task3)
add_subdirectory(task4)

View File

@ -1,27 +0,0 @@
cmake_minimum_required(VERSION 3.14)
project(MonitorExample LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
add_executable(MonitorExample
main.cpp
monitor.h monitor.cpp
producer.h producer.cpp
consumer.h consumer.cpp
)
target_link_libraries(MonitorExample Qt${QT_VERSION_MAJOR}::Core)
include(GNUInstallDirs)
install(TARGETS MonitorExample
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@ -1,26 +0,0 @@
#include "consumer.h"
template<typename T> QSemaphore Consumer<T>::numProducts;
template<typename T> Monitor<T> *Consumer<T>::mon;
template<> void (*Consumer<int>::consume)(int, int) = NULL;
//---------------------------------------
template<typename T> void Consumer<T>::initClass(int numP, Monitor<T> *m, void (*cons)(T, int)) {
numProducts.release(numP);
mon = m;
consume = cons;
}
//---------------------------------------
//Semaphore with Number of Resources -> consume N Resources
//get spot of item in queue, take item, activate producers
//process item
template<typename T> void Consumer<T>::run() {
while (numProducts.tryAcquire()) { // While not all numProducts are consumed:
T* aux = mon->canGet(); // Get pointer to item in itemQ
T item = *aux; // Take the item out of itemQ
mon->doneGetting(aux); // Give info to producer threads
(*consume)(item,ID); // Consume one item
}
}
//---------------------------------------

View File

@ -1,22 +0,0 @@
#ifndef CONSUMER_H
#define CONSUMER_H
#include "monitor.h"
#include <QThread>
#include <QSemaphore>
template<typename T>
class Consumer : public QThread {
private:
int ID;
static Monitor<T> *mon;
static QSemaphore numProducts;
public:
static void (*consume)(T i, int);
static void initClass(int numP, Monitor<T> *m, void (*cons)(T, int));
Consumer<T>(int i) : ID(i) {}
void run();
};
#endif // CONSUMER_H

View File

@ -1,69 +0,0 @@
#include "monitor.h"
template<typename T>
Monitor<T>::Monitor(int n) {
buffer = new T[n];
for(int i=0;i<n;i++)
emptySpotsQ.push(&buffer[i]); // Initialize emptySpotsQ with buffer places
}
//-----------------------------------------
template<typename T>
Monitor<T>::~Monitor() {
delete []buffer;
}
//-----------------------------------------
//producer tries to put an item:
// lock l
// wait for spot in putting queue
// get first spot in putting queue
template<typename T>
T* Monitor<T>::canPut() {
QMutexLocker ml(&l); // Lock entry controlling mutex l
while (emptySpotsQ.size() == 0) // If no free place in emptySpots queue:
full.wait(&l); // Block until condition variable full is given free by mutex l
T *aux = emptySpotsQ.front(); // Get place in emptySpotsQ
emptySpotsQ.pop(); // ?? Free one place in emptySpotsQ ?? (documentation of class queue currently not available)
return aux; // Return pointer to place in emptySpotsQ for item to be produced
}
//-----------------------------------------
//consumer tries to take an item:
// lock l
// wait until items are in itemq
// take item
template<typename T>
T* Monitor<T>::canGet() {
QMutexLocker ml(&l); // Lock entry controlling mutex l
while (itemQ.size() == 0) // If no item in itemQ:
empty.wait(&l); // Block until condition variable empty is given free by mutex l
T* temp = itemQ.front(); // Get item out of itemQ
itemQ.pop(); // ?? Free one place in itemQ ?? (documentation of class queue currently not available)
return temp; // Return pointer to item in itemQ, which will be consumed
}
//-----------------------------------------
//producer is done with producing and wants to put that item:
// lock l
// push produced item to itemQ
// wake waiting consumer
template<typename T>
void Monitor<T>::donePutting(T *x) {
QMutexLocker ml(&l); // Lock entry controlling mutex l
itemQ.push(x); // Push place with produced item into itemQ
empty.wakeOne(); // Notify one consumer thread waiting for condition variable empty
}
//-----------------------------------------
//consumer is done with taking an item:
// lock l
// enlarge producer queue by one
// notify a producer of new spot
template<typename T>
void Monitor<T>::doneGetting(T *x) {
QMutexLocker ml(&l); // Lock entry controlling mutex l
emptySpotsQ.push(x); // Give free the buffer place which had hold the consumed item by pushing in into emptySpotsQ
full.wakeOne(); // Notify one producer thread waiting for condition variable empty
}
//************************************************************

View File

@ -1,31 +0,0 @@
#ifndef MONITOR_H
#define MONITOR_H
#include <QMutexLocker>
#include <QWaitCondition>
#include <queue>
using namespace std;
const int BUFFSIZE = 100;
//************************************************************
template<typename T>
class Monitor {
private:
QMutex l;
QWaitCondition full, empty; // full: Condition variable for queue itemQ.
// empty: Condition variable for queue emptySpotsQ.
queue<T *> emptySpotsQ; // Queue of free item buffer places for items to be produced
queue<T *> itemQ; // Queue of item buffer places with items to be consumed
T *buffer; // Item buffer
public:
T* canPut();
T* canGet();
void donePutting(T *x);
void doneGetting(T *x);
Monitor(int n = BUFFSIZE);
~Monitor();
};
#endif // MONITOR_H

View File

@ -1,28 +0,0 @@
#include "producer.h"
//---------------------------------------
template<typename T> QSemaphore Producer<T>::numProducts;
template<typename T> Monitor<T> * Producer<T>::mon;
template<> int (*Producer<int>::produce)(int) = NULL;
//---------------------------------------
template<typename T> void Producer<T>::initClass(int numP, Monitor<T> *m, T(*prod)(int)) {
mon = m;
numProducts.release(numP);
produce = prod;
}
//---------------------------------------
//Semaphore with Number of Resources -> create N Resources
//produce item -> get spot in queue -> put item into second queue
//activate consumers
template<typename T>
void Producer<T>::run() {
while (numProducts.tryAcquire()) { // While not all numProducts items are produced:
T item = (*produce)(ID); // Produce one item
T* aux = mon->canPut(); // Get place for item in emptySpotsQ
*aux = item; // Put item into emptySpotsQ
mon->donePutting(aux); // Give info to consumer threads
}
}
//---------------------------------------

View File

@ -1,21 +0,0 @@
#ifndef PRODUCER_H
#define PRODUCER_H
#include "monitor.h"
#include <QThread>
#include <QSemaphore>
template<typename T>
class Producer : public QThread {
private:
static QSemaphore numProducts;
int ID;
static Monitor<T> *mon;
public:
static T(*produce)(int);
static void initClass(int numP, Monitor<T> *m, T(*prod)(int));
Producer<T>(int i) : ID(i) {}
void run();
};
#endif // PRODUCER_H

View File

@ -45,7 +45,7 @@ add_executable(task1-sorter)
target_sources(task1-sorter PRIVATE
src/task1-sorter.cpp)
target_include_directories(task1-sorter PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include)
${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(task1-sorter PRIVATE
Qt6::Core)

View File

@ -2,7 +2,9 @@
find_package(Qt6 COMPONENTS Core REQUIRED)
add_executable(task3-chpt3ex12)
target_sources(task3-chpt3ex12 PRIVATE
main.cpp)
target_link_libraries(task3-chpt3ex12 PRIVATE
Qt6::Core)
Qt6::Core)

14
task4/CMakeLists.txt Normal file
View File

@ -0,0 +1,14 @@
find_package(Qt6 COMPONENTS Core REQUIRED)
add_executable(task4-monitor)
target_include_directories(task4-monitor PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(task4-monitor PRIVATE
src/main.cpp
)
target_link_libraries(task4-monitor PRIVATE
Qt6::Core)

36
task4/include/consumer.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include "monitor.h"
#include <QThread>
#include <QSemaphore>
template<typename T>
class Consumer : public QThread {
private:
int ID;
static Monitor<T> *mon;
static QSemaphore numProducts;
public:
static void (*consume)(T i, int);
static void initClass(int numP, Monitor<T> *m, void (*cons)(T, int)) {
numProducts.release(numP);
mon = m;
consume = cons;
};
Consumer(int i) : ID(i) {};
void run() {
while (numProducts.tryAcquire()) { // While not all numProducts are consumed:
T* aux = mon->canGet(); // Get pointer to item in itemQ
T item = *aux; // Take the item out of itemQ
mon->doneGetting(aux); // Give info to producer threads
(*consume)(item,ID); // Consume one item
}
};
};
template<typename T> QSemaphore Consumer<T>::numProducts;
template<typename T> Monitor<T> *Consumer<T>::mon;
template<> void (*Consumer<int>::consume)(int, int) = NULL;

67
task4/include/monitor.h Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include <QMutexLocker>
#include <QWaitCondition>
#include <queue>
using namespace std;
const int BUFFSIZE = 100;
template<typename T>
class Monitor {
private:
QMutex l;
QWaitCondition full, empty;
// full: Condition variable for queue itemQ.
// empty: Condition variable for queue emptySpotsQ.
queue<T *> emptySpotsQ; // Queue of free item buffer places for items to be produced
queue<T *> itemQ; // Queue of item buffer places with items to be consumed
T *buffer; // Item buffer
public:
T *canPut() {
QMutexLocker ml(&l); // Lock entry controlling mutex l
while (emptySpotsQ.size() == 0) // If no free place in emptySpots queue:
full.wait(&l); // Block until condition variable full is given free by mutex l
T *aux = emptySpotsQ.front(); // Get place in emptySpotsQ
emptySpotsQ.pop(); // ?? Free one place in emptySpotsQ ?? (documentation of class queue currently not available)
return aux; // Return pointer to place in emptySpotsQ for item to be produced
};
T *canGet() {
QMutexLocker ml(&l); // Lock entry controlling mutex l
while (itemQ.size() == 0) // If no item in itemQ:
empty.wait(&l); // Block until condition variable empty is given free by mutex l
T *temp = itemQ.front(); // Get item out of itemQ
itemQ.pop(); // ?? Free one place in itemQ ?? (documentation of class queue currently not available)
return temp; // Return pointer to item in itemQ, which will be consumed
};
void donePutting(T *x) {
QMutexLocker ml(&l); // Lock entry controlling mutex l
itemQ.push(x); // Push place with produced item into itemQ
empty.wakeOne(); // Notify one consumer thread waiting for condition variable empty
};
void doneGetting(T *x) {
QMutexLocker ml(&l); // Lock entry controlling mutex l
emptySpotsQ.push(
x); // Give free the buffer place which had hold the consumed item by pushing in into emptySpotsQ
full.wakeOne(); // Notify one producer thread waiting for condition variable empty
};
Monitor(int n = BUFFSIZE) {
buffer = new T[n];
for (int i = 0; i < n; i++)
emptySpotsQ.push(&buffer[i]);
};
~Monitor() {
delete[]buffer;
};
};

38
task4/include/producer.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "monitor.h"
#include <QThread>
#include <QSemaphore>
template<typename T>
class Producer : public QThread {
private:
static QSemaphore numProducts;
int ID;
static Monitor<T> *mon;
public:
static T (*produce)(int);
static void initClass(int numP, Monitor<T> *m, T(*prod)(int)) {
mon = m;
numProducts.release(numP);
produce = prod;
};
Producer(int i) : ID(i) {};
Producer(QObject *parent, int id);
void run() {
while (numProducts.tryAcquire()) { // While not all numProducts items are produced:
T item = (*produce)(ID); // Produce one item
T *aux = mon->canPut(); // Get place for item in emptySpotsQ
*aux = item; // Put item into emptySpotsQ
mon->donePutting(aux); // Give info to consumer threads
}
};
};
template<typename T> QSemaphore Producer<T>::numProducts;
template<typename T> Monitor<T> * Producer<T>::mon;
template<> int (*Producer<int>::produce)(int) = NULL;

View File

@ -1,14 +1,3 @@
/*
============================================================================
Author : G. Barlas
Version : 1.0, September 2015
: 1.1, 16.12.2019 - Comments added (H. Weber)
: 1.2, 27.01.2022 - Console output improved (H. Weber, S. Stahl)
License : V 1.0 released under the GNU GPL 3.0
Description : Producer/consumer example using a monitor.
To compile : qmake monitor2ProdCons.pro; make
============================================================================
*/
#include "monitor.h"
#include "producer.h"
#include "consumer.h"