commit 4853b9ef0a48a066ecfbb60f85bdf6bea9792b4b Author: Lumijiez Date: Sun Dec 8 19:04:50 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f5dcf4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmake-build-debug/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc9b8d1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.29) +project(os-labs) + +set(CMAKE_CXX_STANDARD 23) + +add_executable( + os-labs + main.cpp + src/signal_handler.cpp + include/signal_handler.h + include/buffer.h + src/buffer.cpp + include/producer.h + src/consumer.cpp + include/consumer.h + src/producer.cpp +) +target_link_libraries(os-labs PRIVATE m) +target_include_directories(os-labs PRIVATE ${PROJECT_SOURCE_DIR}/include) \ No newline at end of file diff --git a/include/buffer.h b/include/buffer.h new file mode 100644 index 0000000..0ff0f03 --- /dev/null +++ b/include/buffer.h @@ -0,0 +1,28 @@ +// +// Created by lumijiez on 11/16/24. +// + +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include +#include + +class Buffer { +public: + explicit Buffer(int size); + void produce(int producerId, int item); + int consume(int consumerId); + bool isEmpty() const; + bool isFull() const; + +private: + std::queue items; + const int maxSize; + mutable std::mutex mtx; + std::condition_variable notFull; + std::condition_variable notEmpty; +}; + +#endif //BUFFER_H diff --git a/include/consumer.h b/include/consumer.h new file mode 100644 index 0000000..8e0b0fc --- /dev/null +++ b/include/consumer.h @@ -0,0 +1,22 @@ +// +// Created by lumijiez on 11/16/24. +// + +#ifndef CONSUMER_H +#define CONSUMER_H + +#include "buffer.h" +#include + +class Consumer { +public: + Consumer(int id, Buffer& buffer, std::counting_semaphore<5>& sem); + void run() const; + +private: + int id; + Buffer& buffer; + std::counting_semaphore<5>& consumerSem; +}; + +#endif //CONSUMER_H diff --git a/include/producer.h b/include/producer.h new file mode 100644 index 0000000..507b68e --- /dev/null +++ b/include/producer.h @@ -0,0 +1,22 @@ +// +// Created by lumijiez on 11/16/24. +// + +#ifndef PRODUCER_H +#define PRODUCER_H + +#include "buffer.h" +#include + +class Producer { +public: + Producer(int id, Buffer& buffer, std::counting_semaphore<3>& sem); + void run() const; + +private: + int id; + Buffer& buffer; + std::counting_semaphore<3>& producerSem; +}; + +#endif //PRODUCER_H diff --git a/include/signal_handler.h b/include/signal_handler.h new file mode 100644 index 0000000..cfb8a21 --- /dev/null +++ b/include/signal_handler.h @@ -0,0 +1,18 @@ +// +// Created by lumijiez on 11/16/24. +// + +#ifndef SIGNAL_HANDLER_H +#define SIGNAL_HANDLER_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +void setupSignalHandlers(); + +#endif //SIGNAL_HANDLER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..69e5289 --- /dev/null +++ b/main.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include "signal_handler.h" +#include "buffer.h" +#include "producer.h" +#include "consumer.h" + +[[noreturn]] void runSignalHandler() { + setupSignalHandlers(); + std::cout << "PID: " << getpid() << std::endl; + while (true) { + pause(); + } +} + +void runProducerConsumer() { + Buffer buffer(10); + std::counting_semaphore<3> producerSem(3); + std::counting_semaphore<5> consumerSem(5); + + std::vector producers; + std::vector consumers; + + for (int i = 0; i < 3; ++i) { + producers.emplace_back([i, &buffer, &producerSem]() { + const Producer producer(i, buffer, producerSem); + producer.run(); + }); + } + + for (int i = 0; i < 3; ++i) { + consumers.emplace_back([i, &buffer, &consumerSem]() { + const Consumer consumer(i, buffer, consumerSem); + consumer.run(); + }); + } + + for (auto& p : producers) { + p.join(); + } + for (auto& c : consumers) { + c.join(); + } +} + +int main() { + while (true) { + std::cout << "=== Main Menu ===\n"; + std::cout << "1. Run Signal Handler Program\n"; + std::cout << "2. Run Producer/Consumer Program\n"; + std::cout << "0. Exit\n"; + std::cout << "Enter your choice: "; + + int choice; + std::cin >> choice; + + switch (choice) { + case 1: + std::cout << "Running Signal Handler Program...\n"; + runSignalHandler(); + break; + case 2: + std::cout << "Running Producer/Consumer Program...\n"; + runProducerConsumer(); + break; + case 0: + std::cout << "Exiting program. Goodbye!\n"; + return 0; + default: + std::cout << "Invalid choice. Please try again.\n"; + break; + } + } +} diff --git a/src/buffer.cpp b/src/buffer.cpp new file mode 100644 index 0000000..009d2a1 --- /dev/null +++ b/src/buffer.cpp @@ -0,0 +1,40 @@ +// +// Created by lumijiez on 11/16/24. +// +#include "buffer.h" + +#include + +Buffer::Buffer(const int size) : maxSize(size) {} + +void Buffer::produce(const int producerId, const int item) { + std::unique_lock lock(mtx); + notFull.wait(lock, [this] { return !isFull(); }); + + items.push(item); + std::cout << "Producer " << producerId << " produced: " << item << std::endl; + + lock.unlock(); + notEmpty.notify_one(); +} + +int Buffer::consume(const int consumerId) { + std::unique_lock lock(mtx); + notEmpty.wait(lock, [this] { return !isEmpty(); }); + + const int item = items.front(); + items.pop(); + std::cout << "Consumer " << consumerId << " consumed: " << item << std::endl; + + lock.unlock(); + notFull.notify_one(); + return item; +} + +bool Buffer::isEmpty() const { + return items.empty(); +} + +bool Buffer::isFull() const { + return items.size() >= maxSize; +} \ No newline at end of file diff --git a/src/consumer.cpp b/src/consumer.cpp new file mode 100644 index 0000000..2b2d75d --- /dev/null +++ b/src/consumer.cpp @@ -0,0 +1,18 @@ +// +// Created by lumijiez on 11/16/24. +// +#include "consumer.h" +#include +#include + +Consumer::Consumer(const int id, Buffer& buffer, std::counting_semaphore<5>& sem) + : id(id), buffer(buffer), consumerSem(sem) {} + +void Consumer::run() const { + while (true) { + consumerSem.acquire(); + int item = buffer.consume(id); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + consumerSem.release(); + } +} diff --git a/src/producer.cpp b/src/producer.cpp new file mode 100644 index 0000000..0f7999d --- /dev/null +++ b/src/producer.cpp @@ -0,0 +1,24 @@ +// +// Created by lumijiez on 11/16/24. +// +#include "producer.h" +#include +#include +#include + +Producer::Producer(const int id, Buffer& buffer, std::counting_semaphore<3>& sem) + : id(id), buffer(buffer), producerSem(sem) {} + +void Producer::run() const { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(1, 100); + + while (true) { + producerSem.acquire(); + const int item = dis(gen); + buffer.produce(id, item); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + producerSem.release(); + } +} diff --git a/src/signal_handler.cpp b/src/signal_handler.cpp new file mode 100644 index 0000000..32f5a4f --- /dev/null +++ b/src/signal_handler.cpp @@ -0,0 +1,27 @@ +// +// Created by lumijiez on 11/16/24. +// +#include "signal_handler.h" + +void handleSignal(const int signal) { + if (signal == SIGUSR1) { + std::cout << "SIGUSR1 received" << std::endl; + } else if (signal == SIGUSR2) { + std::random_device rd; + std::default_random_engine generator(rd()); + std::uniform_int_distribution distribution(32, 126); + + for (int i = 0; i < 100; ++i) { + const char randomChar = static_cast(distribution(generator)); + std::cout << randomChar; + } + std::cout << std::endl; + std::exit(0); + } +} + +void setupSignalHandlers() { + std::signal(SIGUSR1, handleSignal); + std::signal(SIGUSR2, handleSignal); +} +