mirror of
https://github.com/ProgramSnail/build_system_2022.git
synced 2025-12-06 00:48:42 +00:00
init
This commit is contained in:
parent
4d899f64a7
commit
b4a7121411
23 changed files with 681 additions and 11 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -1,11 +1,3 @@
|
|||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
lib
|
||||
bim
|
||||
build
|
||||
|
|
|
|||
31
CMakeLists.txt
Normal file
31
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(BuildSystem)
|
||||
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
|
||||
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
|
||||
|
||||
|
||||
set(BUILD_SYSTEM_SOURCES
|
||||
build_graph.cpp
|
||||
builder.cpp
|
||||
thread_pool.cpp
|
||||
task_queue.cpp
|
||||
dependency_manager.cpp
|
||||
task.hpp)
|
||||
|
||||
set (CLI_SOURCES
|
||||
main.cpp
|
||||
interactive_mode.cpp
|
||||
file_mode.cpp
|
||||
cli_common.cpp
|
||||
test_tasks.hpp)
|
||||
|
||||
add_library(BuildSystemLib ${BUILD_SYSTEM_SOURCES})
|
||||
|
||||
add_executable(BuildSystemCli ${CLI_SOURCES})
|
||||
target_link_libraries(BuildSystemCli BuildSystemLib)
|
||||
|
||||
set_property(TARGET BuildSystemLib PROPERTY CXX_STANDARD 20)
|
||||
set_property(TARGET BuildSystemCli PROPERTY CXX_STANDARD 20)
|
||||
9
README.md
Normal file
9
README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
### Build System
|
||||
|
||||
Сборка:
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
|
||||
cmake .. && make
|
||||
```
|
||||
110
build_graph.cpp
Normal file
110
build_graph.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#include "build_graph.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
namespace build_system {
|
||||
|
||||
const size_t BuildGraph::TraversalManager::kCurrentWayEpoch = 0;
|
||||
const size_t BuildGraph::TraversalManager::kNeverVisited = 1;
|
||||
|
||||
class BuildGraph::TraversalManager::View {
|
||||
friend TraversalManager;
|
||||
|
||||
public:
|
||||
View() = delete;
|
||||
|
||||
std::vector<size_t> DFS(size_t vertex) {
|
||||
std::vector<size_t> visited;
|
||||
traversal_manager.DFS(vertex, visited);
|
||||
return visited;
|
||||
}
|
||||
|
||||
// this function saves exsisting values in "visited" array
|
||||
void DFS(size_t vertex, std::vector<size_t>& visited) {
|
||||
traversal_manager.DFS(vertex, visited);
|
||||
}
|
||||
|
||||
virtual ~View() { traversal_manager.nextEpoch(); }
|
||||
|
||||
private:
|
||||
View(TraversalManager &traversal_manager)
|
||||
: traversal_manager(traversal_manager) {}
|
||||
|
||||
private:
|
||||
TraversalManager &traversal_manager;
|
||||
};
|
||||
|
||||
BuildGraph::TraversalManager::View BuildGraph::TraversalManager::getView() {
|
||||
return View(*this);
|
||||
}
|
||||
|
||||
// this function saves existing values in "visited" array
|
||||
void BuildGraph::TraversalManager::DFS(size_t vertex,
|
||||
std::vector<size_t>& current_visited) {
|
||||
if (visited_[vertex] == epoch_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visited_[vertex] == kCurrentWayEpoch) {
|
||||
throw IncorrectBuildGraph{};
|
||||
}
|
||||
|
||||
visited_[vertex] = kCurrentWayEpoch;
|
||||
|
||||
for (auto &dependency : build_graph_.graph_[vertex].dependences) {
|
||||
DFS(dependency, current_visited);
|
||||
}
|
||||
|
||||
visited_[vertex] = epoch_;
|
||||
|
||||
current_visited.push_back(vertex);
|
||||
}
|
||||
|
||||
BuildGraph::BuildGraph(const std::vector<Rule>& rules,
|
||||
std::vector<Task>&& tasks)
|
||||
: traversal_manager_(*this) {
|
||||
graph_.reserve(tasks.size());
|
||||
|
||||
for (size_t i = 0; i < tasks.size(); ++i) {
|
||||
Target target;
|
||||
target.task = std::forward<Task>(tasks[i]);
|
||||
target.id = i;
|
||||
graph_.push_back(target);
|
||||
}
|
||||
|
||||
for (auto &rule : rules) {
|
||||
graph_[rule.target].dependences.push_back(rule.dependency);
|
||||
}
|
||||
|
||||
traversal_manager_.initArray();
|
||||
}
|
||||
|
||||
void BuildGraph::isCorrectOrThrow(size_t target) const {
|
||||
traversal_manager_.getView().DFS(target);
|
||||
}
|
||||
|
||||
bool BuildGraph::isCorrect(size_t target) const {
|
||||
try {
|
||||
isCorrectOrThrow(target);
|
||||
} catch (IncorrectBuildGraph) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Target> BuildGraph::getRequiredTargetsOrder(size_t target) const {
|
||||
|
||||
std::vector<Target> order;
|
||||
|
||||
auto rev_topsorted_required_verticles = traversal_manager_.getView().DFS(target);
|
||||
|
||||
order.reserve(rev_topsorted_required_verticles.size());
|
||||
for (auto &vertex_id : rev_topsorted_required_verticles) {
|
||||
order.push_back(graph_[vertex_id]);
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
} // namespace build_system
|
||||
68
build_graph.hpp
Normal file
68
build_graph.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "task.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
struct IncorrectBuildGraph {};
|
||||
|
||||
struct Rule {
|
||||
size_t target;
|
||||
size_t dependency;
|
||||
};
|
||||
|
||||
struct Target {
|
||||
size_t id;
|
||||
Task task;
|
||||
std::vector<size_t> dependences;
|
||||
};
|
||||
|
||||
class BuildGraph {
|
||||
private:
|
||||
// manage DFS, topsort, etc. safe
|
||||
class TraversalManager {
|
||||
private:
|
||||
class View;
|
||||
|
||||
public:
|
||||
TraversalManager(const BuildGraph& build_graph)
|
||||
: build_graph_(build_graph), epoch_(kNeverVisited + 1) {}
|
||||
|
||||
void initArray() {
|
||||
visited_ = std::vector<size_t>(build_graph_.graph_.size(), kNeverVisited);
|
||||
}
|
||||
|
||||
View getView();
|
||||
|
||||
private:
|
||||
void nextEpoch() { ++epoch_; }
|
||||
|
||||
void DFS(size_t vertex, std::vector<size_t>& current_visited);
|
||||
|
||||
private:
|
||||
static const size_t kCurrentWayEpoch;
|
||||
static const size_t kNeverVisited;
|
||||
|
||||
const BuildGraph &build_graph_;
|
||||
std::vector<size_t> visited_;
|
||||
size_t epoch_;
|
||||
};
|
||||
|
||||
public:
|
||||
BuildGraph(const std::vector<Rule>& rules, std::vector<Task>&& tasks);
|
||||
|
||||
void isCorrectOrThrow(size_t target) const;
|
||||
|
||||
bool isCorrect(size_t target) const;
|
||||
|
||||
std::vector<Target> getRequiredTargetsOrder(size_t target) const;
|
||||
|
||||
private:
|
||||
std::vector<Target> graph_;
|
||||
mutable TraversalManager traversal_manager_;
|
||||
};
|
||||
|
||||
} // namespace build_system
|
||||
18
builder.cpp
Normal file
18
builder.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include "builder.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
void Builder::execute(const BuildGraph& build_graph, size_t target_id) {
|
||||
// can throw IncorrectBuildGraph
|
||||
auto targets_order = build_graph.getRequiredTargetsOrder(target_id);
|
||||
|
||||
for (auto& target : targets_order) {
|
||||
thread_pool_.addTarget(std::move(target.task), target.id, target.dependences);
|
||||
}
|
||||
|
||||
thread_pool_.start();
|
||||
|
||||
thread_pool_.wait();
|
||||
}
|
||||
|
||||
}; // namespace build_system
|
||||
20
builder.hpp
Normal file
20
builder.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "build_graph.hpp"
|
||||
#include "thread_pool.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
explicit Builder(size_t num_threads) : thread_pool_(num_threads) {}
|
||||
|
||||
void execute(const BuildGraph& build_graph, size_t target_id);
|
||||
|
||||
private:
|
||||
ThreadPool thread_pool_;
|
||||
};
|
||||
|
||||
}; // namespace build_system
|
||||
94
cli_common.cpp
Normal file
94
cli_common.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include "cli_common.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "test_tasks.hpp"
|
||||
|
||||
void print(const std::string& message, std::ostream* out) {
|
||||
if (out) {
|
||||
*out << message;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void getParam(const std::string& message, T ¶m, std::istream& in, std::ostream* out) {
|
||||
print(message, out);
|
||||
in >> param;
|
||||
}
|
||||
|
||||
build_system::Builder constructBuilder(std::istream& in, std::ostream* out) {
|
||||
print("Builder constructor\n", out);
|
||||
|
||||
size_t num_threads;
|
||||
getParam("num threads: ", num_threads, in, out);
|
||||
|
||||
return build_system::Builder(num_threads);
|
||||
}
|
||||
|
||||
build_system::BuildGraph constructBuildGraph(std::istream& in, std::ostream* out) {
|
||||
print("BuildGraph constructor\n", out);
|
||||
|
||||
size_t rules_count = 0;
|
||||
getParam("rules count: ", rules_count, in, out);
|
||||
|
||||
std::vector<build_system::Rule> rules;
|
||||
rules.reserve(rules_count);
|
||||
|
||||
print("rules (one per line, in format \"target dependency\"):\n", out);
|
||||
for (size_t i = 0; i < rules_count; ++i) {
|
||||
build_system::Rule rule;
|
||||
in >> rule.target >> rule.dependency;
|
||||
|
||||
--rule.target;
|
||||
--rule.dependency;
|
||||
|
||||
rules.push_back(rule);
|
||||
}
|
||||
|
||||
size_t targets_count = 0;
|
||||
getParam("targets count: ", targets_count, in, out);
|
||||
|
||||
std::vector<build_system::Task> tasks;
|
||||
tasks.reserve(targets_count);
|
||||
|
||||
print("durations of tasks for targets (in seconds): ", out);
|
||||
for (size_t i = 0; i < targets_count; ++i) {
|
||||
size_t duration;
|
||||
in >> duration;
|
||||
|
||||
tasks.push_back(constructTestTask(duration));
|
||||
}
|
||||
|
||||
return build_system::BuildGraph(rules, std::move(tasks));
|
||||
}
|
||||
|
||||
size_t constructTargetId(std::istream& in, std::ostream* out) {
|
||||
size_t target_id;
|
||||
getParam("target id: ", target_id, in, out);
|
||||
|
||||
--target_id;
|
||||
|
||||
return target_id;
|
||||
}
|
||||
|
||||
void execute(build_system::Builder& builder,
|
||||
build_system::BuildGraph& build_graph, size_t target_id,
|
||||
std::ostream* out) {
|
||||
try {
|
||||
auto build_start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
builder.execute(build_graph, target_id);
|
||||
|
||||
auto build_end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto build_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
build_end_time - build_start_time);
|
||||
|
||||
if (out) {
|
||||
*out << "overall time: " << build_time_ms.count() << "ms\n";
|
||||
}
|
||||
|
||||
} catch (build_system::IncorrectBuildGraph) {
|
||||
print("incorrect build graph\n", out);
|
||||
}
|
||||
}
|
||||
26
cli_common.hpp
Normal file
26
cli_common.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
#include "build_graph.hpp"
|
||||
#include "builder.hpp"
|
||||
|
||||
void print(const std::string& message, std::ostream* out);
|
||||
|
||||
template <typename T>
|
||||
void getParam(const std::string& message, T& param, std::istream &in,
|
||||
std::ostream* out);
|
||||
|
||||
build_system::Builder constructBuilder(std::istream& in,
|
||||
std::ostream* out = nullptr);
|
||||
|
||||
build_system::BuildGraph constructBuildGraph(std::istream& in,
|
||||
std::ostream* out = nullptr);
|
||||
|
||||
size_t constructTargetId(std::istream& in, std::ostream* out = nullptr);
|
||||
|
||||
void execute(build_system::Builder& builder,
|
||||
build_system::BuildGraph& build_graph, size_t target_id,
|
||||
std::ostream* out = nullptr);
|
||||
1
compile_flags.txt
Normal file
1
compile_flags.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
-std=c++20
|
||||
44
dependency_manager.cpp
Normal file
44
dependency_manager.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "dependency_manager.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
void DependencyManager::waitAll() {
|
||||
for (size_t i = 0; i < dependency_counters_.size(); ++i) {
|
||||
wait(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DependencyManager::wait(size_t id) {
|
||||
auto &counter = dependency_counters_[id];
|
||||
size_t counter_value = counter.load();
|
||||
while (counter_value != 0) {
|
||||
counter.wait(counter_value);
|
||||
counter_value = counter.load();
|
||||
}
|
||||
}
|
||||
|
||||
size_t DependencyManager::add(size_t id,
|
||||
const std::vector<size_t>& dependences) {
|
||||
size_t new_id = dependency_counters_.size();
|
||||
|
||||
dependency_counters_.emplace_back(dependences.size());
|
||||
|
||||
tasks_consequences_.emplace_back();
|
||||
|
||||
for (auto& dependency_id : dependences) {
|
||||
tasks_consequences_[to_new_id[dependency_id]].push_back(new_id);
|
||||
}
|
||||
|
||||
to_new_id[id] = new_id;
|
||||
return new_id;
|
||||
}
|
||||
|
||||
void DependencyManager::done(size_t id) {
|
||||
for (auto &consequence_id : tasks_consequences_[id]) {
|
||||
if (dependency_counters_[consequence_id].fetch_sub(1) == 1) {
|
||||
dependency_counters_[consequence_id].notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace build_system
|
||||
29
dependency_manager.hpp
Normal file
29
dependency_manager.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace build_system {
|
||||
|
||||
class DependencyManager {
|
||||
public:
|
||||
DependencyManager() {}
|
||||
|
||||
void waitAll(); // async
|
||||
|
||||
void wait(size_t id); // async
|
||||
|
||||
size_t add(size_t id, const std::vector<size_t>& dependences); // sync
|
||||
|
||||
void done(size_t id); // async
|
||||
|
||||
private:
|
||||
std::deque<std::atomic<size_t>> dependency_counters_;
|
||||
std::vector<std::vector<size_t>> tasks_consequences_;
|
||||
std::unordered_map<size_t, size_t> to_new_id;
|
||||
};
|
||||
|
||||
}; // namespace build_system
|
||||
25
file_mode.cpp
Normal file
25
file_mode.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include "file_mode.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "build_graph.hpp"
|
||||
#include "builder.hpp"
|
||||
|
||||
#include "cli_common.hpp"
|
||||
|
||||
void fileMode(const std::string& filename) {
|
||||
std::ifstream in;
|
||||
in.open(filename);
|
||||
|
||||
build_system::Builder builder = constructBuilder(in);
|
||||
|
||||
build_system::BuildGraph build_graph = constructBuildGraph(in);
|
||||
|
||||
size_t target_id = constructTargetId(in);
|
||||
|
||||
execute(builder, build_graph, target_id, &std::cout);
|
||||
|
||||
in.close();
|
||||
}
|
||||
5
file_mode.hpp
Normal file
5
file_mode.hpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
void fileMode(const std::string& filename);
|
||||
20
interactive_mode.cpp
Normal file
20
interactive_mode.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "interactive_mode.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
|
||||
#include "build_graph.hpp"
|
||||
#include "builder.hpp"
|
||||
|
||||
#include "cli_common.hpp"
|
||||
|
||||
void interactiveMode() {
|
||||
build_system::Builder builder = constructBuilder(std::cin, &std::cout);
|
||||
|
||||
build_system::BuildGraph build_graph = constructBuildGraph(std::cin, &std::cout);
|
||||
|
||||
size_t target_id = constructTargetId(std::cin, &std::cout);
|
||||
|
||||
execute(builder, build_graph, target_id, &std::cout);
|
||||
|
||||
}
|
||||
3
interactive_mode.hpp
Normal file
3
interactive_mode.hpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void interactiveMode();
|
||||
10
main.cpp
Normal file
10
main.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "interactive_mode.hpp"
|
||||
#include "file_mode.hpp"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
interactiveMode();
|
||||
} else {
|
||||
fileMode(argv[1]);
|
||||
}
|
||||
}
|
||||
12
task.hpp
Normal file
12
task.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace build_system {
|
||||
|
||||
using Task = std::function<void()>;
|
||||
|
||||
using IdentTask = std::pair<Task, size_t>;
|
||||
|
||||
}; // namespace build_system
|
||||
30
task_queue.cpp
Normal file
30
task_queue.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "task_queue.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
bool TaskQueue::addIdentTask(IdentTask&& task) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (is_closed_) {
|
||||
return false;
|
||||
}
|
||||
tasks_.push_back(std::move(task));
|
||||
task_exist_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<IdentTask> TaskQueue::getIdentTask() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (tasks_.empty() && !is_closed_) {
|
||||
task_exist_.wait(lock);
|
||||
}
|
||||
if (tasks_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
IdentTask task = tasks_.front();
|
||||
tasks_.pop_front();
|
||||
|
||||
return std::move(task);
|
||||
}
|
||||
|
||||
}; // namespace build_system
|
||||
33
task_queue.hpp
Normal file
33
task_queue.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include "task.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
class TaskQueue {
|
||||
public:
|
||||
TaskQueue() : is_closed_(false) {}
|
||||
|
||||
bool addIdentTask(IdentTask&& task);
|
||||
|
||||
std::optional<IdentTask> getIdentTask();
|
||||
|
||||
void close() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
is_closed_ = true;
|
||||
task_exist_.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
std::deque<IdentTask> tasks_;
|
||||
bool is_closed_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable task_exist_;
|
||||
};
|
||||
|
||||
}; // namespace build_system
|
||||
13
test_tasks.hpp
Normal file
13
test_tasks.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <thread>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "task.hpp"
|
||||
|
||||
inline build_system::Task constructTestTask(size_t duration) {
|
||||
return [duration]() {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(duration));
|
||||
};
|
||||
}
|
||||
47
thread_pool.cpp
Normal file
47
thread_pool.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#include "thread_pool.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "task.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
void ThreadPool::addTarget(Task&& task, size_t id,
|
||||
const std::vector<size_t>& dependences) {
|
||||
size_t new_id = dependency_manager_.add(id, dependences);
|
||||
task_queue_.addIdentTask({std::move(task), new_id});
|
||||
}
|
||||
|
||||
void ThreadPool::start() {
|
||||
threads_.reserve(num_threads_);
|
||||
for (size_t i = 0; i < num_threads_; ++i) {
|
||||
threads_.emplace_back([this]() {
|
||||
while (true) {
|
||||
auto may_be_task = task_queue_.getIdentTask();
|
||||
if (may_be_task == std::nullopt) {
|
||||
break;
|
||||
}
|
||||
|
||||
dependency_manager_.wait(may_be_task.value().second);
|
||||
|
||||
try {
|
||||
may_be_task.value().first();
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
dependency_manager_.done(may_be_task.value().second);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::wait() {
|
||||
task_queue_.close();
|
||||
dependency_manager_.waitAll();
|
||||
|
||||
for (auto& thread : threads_) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace build_system
|
||||
30
thread_pool.hpp
Normal file
30
thread_pool.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "dependency_manager.hpp"
|
||||
#include "task_queue.hpp"
|
||||
|
||||
namespace build_system {
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t num_threads) : num_threads_(num_threads) {}
|
||||
|
||||
void addTarget(Task&& task, size_t id, const std::vector<size_t>& dependences);
|
||||
|
||||
void start();
|
||||
|
||||
void wait();
|
||||
|
||||
private:
|
||||
size_t num_threads_;
|
||||
std::vector<std::thread> threads_;
|
||||
TaskQueue task_queue_;
|
||||
DependencyManager dependency_manager_;
|
||||
};
|
||||
|
||||
}; // namespace build_system
|
||||
Loading…
Add table
Add a link
Reference in a new issue