Initial commit

This commit is contained in:
2024-12-08 19:04:50 +02:00
commit 4853b9ef0a
11 changed files with 295 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
cmake-build-debug/

19
CMakeLists.txt Normal file
View File

@@ -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)

28
include/buffer.h Normal file
View File

@@ -0,0 +1,28 @@
//
// Created by lumijiez on 11/16/24.
//
#ifndef BUFFER_H
#define BUFFER_H
#include <queue>
#include <mutex>
#include <condition_variable>
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<int> items;
const int maxSize;
mutable std::mutex mtx;
std::condition_variable notFull;
std::condition_variable notEmpty;
};
#endif //BUFFER_H

22
include/consumer.h Normal file
View File

@@ -0,0 +1,22 @@
//
// Created by lumijiez on 11/16/24.
//
#ifndef CONSUMER_H
#define CONSUMER_H
#include "buffer.h"
#include <semaphore>
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

22
include/producer.h Normal file
View File

@@ -0,0 +1,22 @@
//
// Created by lumijiez on 11/16/24.
//
#ifndef PRODUCER_H
#define PRODUCER_H
#include "buffer.h"
#include <semaphore>
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

18
include/signal_handler.h Normal file
View File

@@ -0,0 +1,18 @@
//
// Created by lumijiez on 11/16/24.
//
#ifndef SIGNAL_HANDLER_H
#define SIGNAL_HANDLER_H
#include <cmath>
#include <iostream>
#include <csignal>
#include <cstdlib>
#include <stdexcept>
#include <limits>
#include <cstdint>
#include <bits/random.h>
#include <random>
void setupSignalHandlers();
#endif //SIGNAL_HANDLER_H

76
main.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
#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<std::thread> producers;
std::vector<std::thread> 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;
}
}
}

40
src/buffer.cpp Normal file
View File

@@ -0,0 +1,40 @@
//
// Created by lumijiez on 11/16/24.
//
#include "buffer.h"
#include <iostream>
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;
}

18
src/consumer.cpp Normal file
View File

@@ -0,0 +1,18 @@
//
// Created by lumijiez on 11/16/24.
//
#include "consumer.h"
#include <chrono>
#include <thread>
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();
}
}

24
src/producer.cpp Normal file
View File

@@ -0,0 +1,24 @@
//
// Created by lumijiez on 11/16/24.
//
#include "producer.h"
#include <random>
#include <chrono>
#include <thread>
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();
}
}

27
src/signal_handler.cpp Normal file
View File

@@ -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<char>(distribution(generator));
std::cout << randomChar;
}
std::cout << std::endl;
std::exit(0);
}
}
void setupSignalHandlers() {
std::signal(SIGUSR1, handleSignal);
std::signal(SIGUSR2, handleSignal);
}