diff --git a/task1/main.cpp b/task1/main.cpp index 6297ca5..0a31d51 100644 --- a/task1/main.cpp +++ b/task1/main.cpp @@ -62,14 +62,16 @@ auto main(int argc, char *argv[]) -> int { auto delay_ms = std::chrono::duration_cast(t2 - t1); fmt::print("Sorted {} entries within {} ms in sequential\n", dataset_seq.size(), delay_ms.count()); + + static constexpr int nthreads = 16; t1 = std::chrono::high_resolution_clock::now(); algo::MergeSort_v2::sort(dataset_par.begin(), dataset_par.end(), [](int32_t a, int32_t b) { return (a > b); - }, 16); + }, nthreads); t2 = std::chrono::high_resolution_clock::now(); delay_ms = std::chrono::duration_cast(t2 - t1); - fmt::print("Sorted {} entries within {} ms in parallel using {} threads\n", dataset_seq.size(), delay_ms.count(), 16); + fmt::print("Sorted {} entries within {} ms in parallel using {} threads\n", dataset_seq.size(), delay_ms.count(), nthreads); auto eq = (dataset_seq == dataset_par); fmt::print("Equality: {}\n", eq); diff --git a/task1/mergesort.h b/task1/mergesort.h index 18d4ef7..18377aa 100644 --- a/task1/mergesort.h +++ b/task1/mergesort.h @@ -83,10 +83,9 @@ namespace algo { class MergeSort_v2 { private: - //Caution: non thread-safe, must be executed with additional protection (e.g. lock_guard) template static auto - merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> 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; @@ -116,20 +115,23 @@ namespace algo { output_start++; } + dataset_guard.lock(); const auto size = std::distance(start_m, end); for (auto i = 0; i <= size; i++, start_m++, begin++) { *start_m = *begin; } + dataset_guard.unlock(); } template static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start, - int &nthreads, std::mutex &dataset_guard, std::mutex &depth_guard) -> void { + int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void { Iterator mid = start; Iterator begin = output_start; if (std::distance(start, end) < 1) { + //Quit on smalles list size (one element is always sorted) return; } else { if (nthreads > 1) { @@ -151,8 +153,7 @@ namespace algo { //merge everything together starting from the complete beginning t1.join(); t2.join(); - const std::lock_guard lock(dataset_guard); - merge(start, mid, end, cmp, begin); + merge(start, mid, end, cmp, begin, dataset_guard); } else { //move mid iterator litterally to the mid std::advance(mid, std::distance(start, end) / 2); @@ -165,8 +166,7 @@ namespace algo { ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); //merge everything together starting from the complete beginning - const std::lock_guard lock(dataset_guard); - merge(start, mid, end, cmp, begin); + merge(start, mid, end, cmp, begin, dataset_guard); } } } @@ -176,7 +176,7 @@ namespace algo { static auto sort(Iterator start, Iterator end, Comparator cmp, int nthreads) -> void { using valtype = typename std::iterator_traits::value_type; std::vector temporary_dataset(std::distance(start, end)); - std::mutex dataset_guard; + 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);