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