initial commit
This commit is contained in:
commit
5da509e373
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cmake-build-debug/
|
17
CMakeLists.txt
Normal file
17
CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
project(task1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_executable(task1 src/threadpool/main.cpp
|
||||
src/threadpool/counter.cpp
|
||||
include/counter.h
|
||||
src/threadpool/sum.cpp
|
||||
include/sum.h
|
||||
src/threadpool/threadPool.cpp
|
||||
include/threadPool.h)
|
||||
|
||||
add_executable(task1_async src/async.cpp
|
||||
include/async.h
|
||||
)
|
||||
add_executable(sync src/sync.cpp include/sync.h)
|
14
include/async.h
Normal file
14
include/async.h
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 02/07/2024.
|
||||
//
|
||||
|
||||
#ifndef TASK1_ASYNC_H
|
||||
#define TASK1_ASYNC_H
|
||||
|
||||
|
||||
class async {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //TASK1_ASYNC_H
|
20
include/counter.h
Normal file
20
include/counter.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifndef TASK1_COUNTER_H
|
||||
#define TASK1_COUNTER_H
|
||||
|
||||
|
||||
class Counter {
|
||||
public:
|
||||
Counter();
|
||||
int getNext();
|
||||
private:
|
||||
std::atomic<int> value;
|
||||
};
|
||||
|
||||
|
||||
#endif //TASK1_COUNTER_H
|
24
include/sum.h
Normal file
24
include/sum.h
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifndef TASK1_SUM_H
|
||||
#define TASK1_SUM_H
|
||||
|
||||
|
||||
// Thread-safe sum accumulator
|
||||
class SumAccumulator {
|
||||
public:
|
||||
void add(int value);
|
||||
|
||||
long long getTotal();
|
||||
|
||||
private:
|
||||
long long sum = 0;
|
||||
std::mutex mtx;
|
||||
};
|
||||
|
||||
|
||||
#endif //TASK1_SUM_H
|
14
include/sync.h
Normal file
14
include/sync.h
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 02/07/2024.
|
||||
//
|
||||
|
||||
#ifndef TASK1_SYNC_H
|
||||
#define TASK1_SYNC_H
|
||||
|
||||
|
||||
class sync {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //TASK1_SYNC_H
|
50
include/threadPool.h
Normal file
50
include/threadPool.h
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#ifndef TASK1_THREADPOOL_H
|
||||
#define TASK1_THREADPOOL_H
|
||||
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
using namespace std;
|
||||
|
||||
// Class that represents a simple thread pool
|
||||
class ThreadPool {
|
||||
public:
|
||||
// // Constructor to creates a thread pool with given
|
||||
// number of threads
|
||||
ThreadPool(size_t num_threads);
|
||||
|
||||
// Destructor to stop the thread pool
|
||||
~ThreadPool();
|
||||
|
||||
// Enqueue task for execution by the thread pool
|
||||
void enqueue(function<void()> task);
|
||||
|
||||
private:
|
||||
// Vector to store worker threads
|
||||
vector<thread> threads_;
|
||||
|
||||
// Queue of tasks
|
||||
queue<function<void()> > tasks_;
|
||||
|
||||
// Mutex to synchronize access to shared data
|
||||
mutex queue_mutex_;
|
||||
|
||||
// Condition variable to signal changes in the state of
|
||||
// the tasks queue
|
||||
condition_variable cv_;
|
||||
|
||||
// Flag to indicate whether the thread pool should stop
|
||||
// or not
|
||||
bool stop_ = false;
|
||||
};
|
||||
|
||||
|
||||
#endif //TASK1_THREADPOOL_H
|
77
src/async.cpp
Normal file
77
src/async.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <future>
|
||||
|
||||
// Thread-safe counter class
|
||||
class Counter {
|
||||
private:
|
||||
std::atomic<int> value;
|
||||
public:
|
||||
Counter() : value(0) {}
|
||||
int next() {
|
||||
return ++value;
|
||||
}
|
||||
};
|
||||
|
||||
// Thread-safe sum class
|
||||
class SumAccumulator {
|
||||
private:
|
||||
std::atomic<long long> total;
|
||||
public:
|
||||
SumAccumulator() : total(0) {}
|
||||
void add(int value) {
|
||||
total.fetch_add(value, std::memory_order_relaxed);
|
||||
}
|
||||
long long getTotal() const {
|
||||
return total.load(std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
|
||||
// Service function that reads the counter value, sleeps, and returns the value
|
||||
int service(Counter& counter) {
|
||||
int value = counter.next();
|
||||
// Sleep for a random amount of time up to 1 second
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(1, 1000);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
|
||||
return value;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Counter counter;
|
||||
SumAccumulator sumAccumulator;
|
||||
|
||||
const int totalCalls = 1000; // 1 million times
|
||||
|
||||
// Vector to hold future objects
|
||||
std::vector<std::future<void>> futures;
|
||||
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Launching async tasks
|
||||
for (int i = 0; i < totalCalls; ++i) {
|
||||
futures.push_back(std::async(std::launch::async, [&counter, &sumAccumulator] {
|
||||
int value = service(counter);
|
||||
sumAccumulator.add(value);
|
||||
}));
|
||||
}
|
||||
|
||||
// Wait for all tasks to complete
|
||||
for (auto& fut : futures) {
|
||||
fut.get();
|
||||
}
|
||||
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> duration = endTime - startTime;
|
||||
|
||||
// Final total should be 500,000,500,000
|
||||
std::cout << "Final Total: " << sumAccumulator.getTotal() << std::endl;
|
||||
std::cout << "Execution Time: " << duration.count() << " seconds" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
65
src/sync.cpp
Normal file
65
src/sync.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include "thread"
|
||||
|
||||
// Thread-safe counter class
|
||||
class Counter {
|
||||
private:
|
||||
int value;
|
||||
public:
|
||||
Counter() : value(0) {}
|
||||
int next() {
|
||||
return ++value;
|
||||
}
|
||||
};
|
||||
|
||||
// Thread-safe sum class
|
||||
class SumAccumulator {
|
||||
private:
|
||||
long total;
|
||||
public:
|
||||
SumAccumulator() : total(0) {}
|
||||
void add(int value) {
|
||||
total += value;
|
||||
}
|
||||
long getTotal() const {
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
// Service function that reads the counter value, sleeps, and returns the value
|
||||
int service(Counter& counter) {
|
||||
int value = counter.next();
|
||||
// Sleep for a random amount of time up to 1 second
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(1, 1000);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
|
||||
return value;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Counter counter;
|
||||
SumAccumulator sumAccumulator;
|
||||
|
||||
const int totalCalls = 100; // 1 million times
|
||||
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Run the service synchronously
|
||||
for (int i = 0; i < totalCalls; ++i) {
|
||||
int value = service(counter);
|
||||
sumAccumulator.add(value);
|
||||
}
|
||||
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> duration = endTime - startTime;
|
||||
|
||||
// Final total should be 500,000,500,000
|
||||
std::cout << "Final Total: " << sumAccumulator.getTotal() << std::endl;
|
||||
std::cout << "Execution Time: " << duration.count() << " seconds" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
11
src/threadpool/counter.cpp
Normal file
11
src/threadpool/counter.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#include "../../include/counter.h"
|
||||
|
||||
Counter::Counter() : value(0) {}
|
||||
|
||||
int Counter::getNext() {
|
||||
return ++value;
|
||||
}
|
63
src/threadpool/main.cpp
Normal file
63
src/threadpool/main.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <future>
|
||||
#include "../../include/counter.h"
|
||||
#include "../../include/sum.h"
|
||||
#include "../../include/threadPool.h"
|
||||
|
||||
// Simulated service function
|
||||
int service(Counter& counter) {
|
||||
int value = counter.getNext();
|
||||
|
||||
// Sleep for a random amount of time up to 1 second
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(0, 1000);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen)));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int main() {
|
||||
const int numCalls1 = 10000;
|
||||
const int maxThreads1 = 100;
|
||||
|
||||
Counter counter;
|
||||
SumAccumulator sumAccumulator;
|
||||
|
||||
auto worker = [&counter, &sumAccumulator]() {
|
||||
int value = service(counter);
|
||||
sumAccumulator.add(value);
|
||||
};
|
||||
|
||||
ThreadPool pool(maxThreads1);
|
||||
|
||||
std::cout << "Running service " << numCalls1 << " times with up to " << maxThreads1 << " threads..." << std::endl;
|
||||
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Enqueue tasks for execution
|
||||
for (int i = 0; i < numCalls1; ++i) {
|
||||
pool.enqueue([&worker] {
|
||||
worker();
|
||||
});
|
||||
}
|
||||
|
||||
// Wait for all tasks to complete
|
||||
pool.~ThreadPool();
|
||||
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> duration = endTime - startTime;
|
||||
|
||||
std::cout << "Final Total: " << sumAccumulator.getTotal() << std::endl;
|
||||
std::cout << "Execution Time: " << duration.count() << " seconds" << std::endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
16
src/threadpool/sum.cpp
Normal file
16
src/threadpool/sum.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#include "../../include/sum.h"
|
||||
|
||||
|
||||
void SumAccumulator::add(int value) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
sum += value;
|
||||
}
|
||||
|
||||
long long SumAccumulator::getTotal() {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
return sum;
|
||||
}
|
71
src/threadpool/threadPool.cpp
Normal file
71
src/threadpool/threadPool.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// Created by Christopher Hamer on 19/06/2024.
|
||||
//
|
||||
|
||||
#include "../../include/threadPool.h"
|
||||
|
||||
ThreadPool::ThreadPool(size_t num_threads) {
|
||||
|
||||
// Creating worker threads
|
||||
for (size_t i = 0; i < num_threads; ++i) {
|
||||
threads_.emplace_back([this] {
|
||||
while (true) {
|
||||
function<void()> task;
|
||||
// The reason for putting the below code
|
||||
// here is to unlock the queue before
|
||||
// executing the task so that other
|
||||
// threads can perform enqueue tasks
|
||||
{
|
||||
// Locking the queue so that data
|
||||
// can be shared safely
|
||||
unique_lock<mutex> lock(
|
||||
queue_mutex_);
|
||||
|
||||
// Waiting until there is a task to
|
||||
// execute or the pool is stopped
|
||||
cv_.wait(lock, [this] {
|
||||
return !tasks_.empty() || stop_;
|
||||
});
|
||||
|
||||
// exit the thread in case the pool
|
||||
// is stopped and there are no tasks
|
||||
if (stop_ && tasks_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the next task from the queue
|
||||
task = move(tasks_.front());
|
||||
tasks_.pop();
|
||||
}
|
||||
|
||||
task();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
{
|
||||
// Lock the queue to update the stop flag safely
|
||||
unique_lock<mutex> lock(queue_mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
|
||||
// Notify all threads
|
||||
cv_.notify_all();
|
||||
|
||||
// Joining all worker threads to ensure they have
|
||||
// completed their tasks
|
||||
for (auto& thread : threads_) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(function<void()> task) {
|
||||
{
|
||||
unique_lock<std::mutex> lock(queue_mutex_);
|
||||
tasks_.emplace(move(task));
|
||||
}
|
||||
cv_.notify_one();
|
||||
}
|
Loading…
Reference in New Issue
Block a user