diff --git a/BarlasChpt3Ex12/CMakeLists.txt b/BarlasChpt3Ex12/CMakeLists.txt deleted file mode 100644 index 3a7a3d4..0000000 --- a/BarlasChpt3Ex12/CMakeLists.txt +++ /dev/null @@ -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} -) diff --git a/BarlasChpt3Ex12/main.cpp b/BarlasChpt3Ex12/main.cpp deleted file mode 100644 index 099cd9f..0000000 --- a/BarlasChpt3Ex12/main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include - -/* - * 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; -} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a6e44c..afc6e34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,4 +26,5 @@ add_subdirectory(third-party/fmt) # Include CMakeLists files from subdirs for specific tasks add_subdirectory(task1) -add_subdirectory(task3) \ No newline at end of file +add_subdirectory(task3) +add_subdirectory(task4) \ No newline at end of file diff --git a/MonitorExample/CMakeLists.txt b/MonitorExample/CMakeLists.txt deleted file mode 100644 index c116e0f..0000000 --- a/MonitorExample/CMakeLists.txt +++ /dev/null @@ -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} -) diff --git a/MonitorExample/consumer.cpp b/MonitorExample/consumer.cpp deleted file mode 100644 index 528e052..0000000 --- a/MonitorExample/consumer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "consumer.h" - -template QSemaphore Consumer::numProducts; -template Monitor *Consumer::mon; -template<> void (*Consumer::consume)(int, int) = NULL; - -//--------------------------------------- -template void Consumer::initClass(int numP, Monitor *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 void Consumer::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 - } -} -//--------------------------------------- diff --git a/MonitorExample/consumer.h b/MonitorExample/consumer.h deleted file mode 100644 index 719cc02..0000000 --- a/MonitorExample/consumer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CONSUMER_H -#define CONSUMER_H - -#include "monitor.h" -#include -#include - -template -class Consumer : public QThread { -private: - int ID; - static Monitor *mon; - static QSemaphore numProducts; -public: - static void (*consume)(T i, int); - static void initClass(int numP, Monitor *m, void (*cons)(T, int)); - - Consumer(int i) : ID(i) {} - void run(); -}; - -#endif // CONSUMER_H diff --git a/MonitorExample/monitor.cpp b/MonitorExample/monitor.cpp deleted file mode 100644 index b1ace5e..0000000 --- a/MonitorExample/monitor.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "monitor.h" - -template -Monitor::Monitor(int n) { - buffer = new T[n]; - for(int i=0;i -Monitor::~Monitor() { - delete []buffer; -} -//----------------------------------------- - -//producer tries to put an item: -// lock l -// wait for spot in putting queue -// get first spot in putting queue -template -T* Monitor::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 -T* Monitor::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 -void Monitor::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 -void Monitor::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 -} -//************************************************************ diff --git a/MonitorExample/monitor.h b/MonitorExample/monitor.h deleted file mode 100644 index 55894d1..0000000 --- a/MonitorExample/monitor.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef MONITOR_H -#define MONITOR_H -#include -#include -#include - -using namespace std; - -const int BUFFSIZE = 100; -//************************************************************ - -template -class Monitor { -private: - QMutex l; - QWaitCondition full, empty; // full: Condition variable for queue itemQ. - // empty: Condition variable for queue emptySpotsQ. - - queue emptySpotsQ; // Queue of free item buffer places for items to be produced - queue 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 diff --git a/MonitorExample/producer.cpp b/MonitorExample/producer.cpp deleted file mode 100644 index 4f49812..0000000 --- a/MonitorExample/producer.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "producer.h" - -//--------------------------------------- -template QSemaphore Producer::numProducts; -template Monitor * Producer::mon; -template<> int (*Producer::produce)(int) = NULL; -//--------------------------------------- - -template void Producer::initClass(int numP, Monitor *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 -void Producer::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 - } -} -//--------------------------------------- diff --git a/MonitorExample/producer.h b/MonitorExample/producer.h deleted file mode 100644 index f47d4ec..0000000 --- a/MonitorExample/producer.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef PRODUCER_H -#define PRODUCER_H -#include "monitor.h" -#include -#include - -template -class Producer : public QThread { -private: - static QSemaphore numProducts; - int ID; - static Monitor *mon; -public: - static T(*produce)(int); - static void initClass(int numP, Monitor *m, T(*prod)(int)); - - Producer(int i) : ID(i) {} - void run(); -}; - -#endif // PRODUCER_H diff --git a/task1/CMakeLists.txt b/task1/CMakeLists.txt index 819dda1..1183a12 100644 --- a/task1/CMakeLists.txt +++ b/task1/CMakeLists.txt @@ -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) diff --git a/task3/CMakeLists.txt b/task3/CMakeLists.txt index 4081dd2..ad8f6b9 100644 --- a/task3/CMakeLists.txt +++ b/task3/CMakeLists.txt @@ -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) \ No newline at end of file + Qt6::Core) \ No newline at end of file diff --git a/task4/CMakeLists.txt b/task4/CMakeLists.txt new file mode 100644 index 0000000..c22a3f3 --- /dev/null +++ b/task4/CMakeLists.txt @@ -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) diff --git a/task4/include/consumer.h b/task4/include/consumer.h new file mode 100644 index 0000000..ee9ff8f --- /dev/null +++ b/task4/include/consumer.h @@ -0,0 +1,36 @@ +#pragma once + +#include "monitor.h" +#include +#include + +template +class Consumer : public QThread { +private: + int ID; + static Monitor *mon; + static QSemaphore numProducts; +public: + static void (*consume)(T i, int); + + static void initClass(int numP, Monitor *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 QSemaphore Consumer::numProducts; +template Monitor *Consumer::mon; +template<> void (*Consumer::consume)(int, int) = NULL; \ No newline at end of file diff --git a/task4/include/monitor.h b/task4/include/monitor.h new file mode 100644 index 0000000..184c77c --- /dev/null +++ b/task4/include/monitor.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +using namespace std; + +const int BUFFSIZE = 100; + +template +class Monitor { +private: + QMutex l; + QWaitCondition full, empty; + // full: Condition variable for queue itemQ. + // empty: Condition variable for queue emptySpotsQ. + + queue emptySpotsQ; // Queue of free item buffer places for items to be produced + queue 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; + }; +}; diff --git a/task4/include/producer.h b/task4/include/producer.h new file mode 100644 index 0000000..f73bc05 --- /dev/null +++ b/task4/include/producer.h @@ -0,0 +1,38 @@ +#pragma once + +#include "monitor.h" +#include +#include + +template +class Producer : public QThread { +private: + static QSemaphore numProducts; + int ID; + static Monitor *mon; +public: + static T (*produce)(int); + + static void initClass(int numP, Monitor *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 QSemaphore Producer::numProducts; +template Monitor * Producer::mon; +template<> int (*Producer::produce)(int) = NULL; \ No newline at end of file diff --git a/MonitorExample/main.cpp b/task4/src/main.cpp similarity index 72% rename from MonitorExample/main.cpp rename to task4/src/main.cpp index e589af5..9c2e4ba 100644 --- a/MonitorExample/main.cpp +++ b/task4/src/main.cpp @@ -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"