diff --git a/task1/main.cpp b/task1/main.cpp index 0a31d51..0a01ede 100644 --- a/task1/main.cpp +++ b/task1/main.cpp @@ -63,9 +63,9 @@ auto main(int argc, char *argv[]) -> int { fmt::print("Sorted {} entries within {} ms in sequential\n", dataset_seq.size(), delay_ms.count()); - static constexpr int nthreads = 16; + const int nthreads = std::thread::hardware_concurrency(); t1 = std::chrono::high_resolution_clock::now(); - algo::MergeSort_v2::sort(dataset_par.begin(), dataset_par.end(), [](int32_t a, int32_t b) { + algo::MergeSort_mt::sort(dataset_par, [](int32_t a, int32_t b) { return (a > b); }, nthreads); t2 = std::chrono::high_resolution_clock::now(); diff --git a/task1/mergesort.h b/task1/mergesort.h index ecd942a..c798079 100644 --- a/task1/mergesort.h +++ b/task1/mergesort.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace algo { @@ -84,15 +86,42 @@ namespace algo { class MergeSort_v2 { private: - template + template static auto - mt_merge() { + mt_merge(Container left, Container right, Comparator cmp) -> Container { + //using Iterator = typename std::iterator_traits::value_type; + Container output; + + auto lefti = left.begin(); + auto righti = right.begin(); + + while (lefti < left.end() && righti < right.end()) { + if (cmp(*lefti, *righti)) { + output.emplace_back(std::move(*lefti)); + lefti++; + } else { + output.emplace_back(std::move(*righti)); + righti++; + } + } + + while (lefti < left.end()) { + output.emplace_back(std::move(*lefti)); + lefti++; + } + while (righti < right.end()) { + output.emplace_back(std::move(*righti)); + righti++; + } + + return output; } template static auto - merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start, std::recursive_mutex &dataset_guard) -> void { + merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start, + std::recursive_mutex &dataset_guard) -> void { Iterator start_m = start; Iterator begin = output_start; Iterator start2 = middle + 1; @@ -131,6 +160,69 @@ namespace algo { } + template + static auto mt_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start, + int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void { + Iterator mid = start; + Iterator to_start = output_start; + + if (std::distance(start, end) < 1) { + return; + + } + + bool rem_threads; + { + std::lock_guard guard(depth_guard); //RAII guard + rem_threads = nthreads > 1; + } + + if (rem_threads) { + { + std::lock_guard guard(depth_guard); //RAII guard + nthreads -= 2; + } + + std::advance(mid, std::distance(start, end) / 2); + std::thread t1([&]() { + mt_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); + }); + + std::advance(output_start, std::distance(start, mid + 1)); + std::thread t2([&]() { + mt_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); + }); + + + //merge everything together starting from the complete beginning + t1.join(); + t2.join(); + std::vector left; + left.assign(start, mid); + std::vector right; + right.assign(mid + 1, end); + + mt_merge(left, right, cmp); + } else { + //move mid iterator litterally to the mid + std::advance(mid, std::distance(start, end) / 2); + //sort the first half within an recursion + mt_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); + + //move output iterator + std::advance(output_start, std::distance(start, mid + 1)); + //sort the second half within a recursion + mt_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); + + std::vector left; + left.assign(start, mid); + std::vector right; + right.assign(mid + 1, end); + + mt_merge(left, right, cmp); + } + } + template static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start, int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void { @@ -149,12 +241,16 @@ namespace algo { std::advance(mid, std::distance(start, end) / 2); //sort the first half within an recursion - std::thread t1([&]() { ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); }); + std::thread t1([&]() { + ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); + }); //move output iteratoroutput_vec, start, mid, cmp, output_start std::advance(output_start, std::distance(start, mid + 1)); //sort the second half within a recursion - std::thread t2([&]() { ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); }); + std::thread t2([&]() { + ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); + }); //merge everything together starting from the complete beginning @@ -186,8 +282,87 @@ namespace algo { std::recursive_mutex dataset_guard; std::mutex depth_guard; - ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, depth_guard); + mt_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, + depth_guard); } }; + class MergeSort_mt { + + template + static auto + merge(typename std::vector::iterator mid, std::vector &left, std::vector &right, + Comparator cmp, std::mutex &mut) { + { + std::lock_guard lock(mut); + + auto l = left.begin(); + auto r = right.begin(); + + while (l < left.end() && r < right.end()) { + if (cmp(*l, *r)) { + *mid = *l; + l++; + } else { + *mid = *r; + r++; + } + mid++; + } + while (l < left.end()) { + *mid = *l; + mid++; + l++; + } + while (r < right.end()) { + *mid = *r; + mid++; + r++; + } + } + } + + template + static auto split(std::vector &data, std::vector &outdata, Comparator cmp, int depth, int &num_threads, std::mutex &mut) { + if (data.size() <= 1) { + return; + } + + auto mid = data.begin(); + std::advance(mid, std::distance(data.begin(), data.end()) / 2); + + + + + std::vector left(std::make_move_iterator(data.begin()), std::make_move_iterator(mid)); + std::vector right(std::make_move_iterator(mid), std::make_move_iterator(data.end())); + + if (depth < num_threads) { + std::thread left_thread([&]() { split(left, outdata, cmp, depth + 1, num_threads, mut); }); + std::thread right_thread([&]() { split(right, outdata, cmp, depth + 1, num_threads, mut); }); + + left_thread.join(); + right_thread.join(); + } else { + split(left, outdata, cmp, depth + 1, num_threads, mut); + split(right, outdata, cmp, depth + 1, num_threads, mut); + } + + + mid = outdata.begin(); + std::advance(mid, std::distance(outdata.begin(), outdata.end())/2); + merge(mid, left, right, cmp, mut); + } + + public: + template + static auto + sort(std::vector &data, Comparator cmp, int num_threads = std::thread::hardware_concurrency()) -> void { + std::vector local_result = data; + std::mutex local_result_lock; + + split(data, local_result, cmp, 0, num_threads, local_result_lock); + data = local_result; + } + }; } \ No newline at end of file