#include #include #include #include #include #include #include #include #include #include #include #include #include // ================= CONFIG ================= constexpr int kDefaultN = 20000; constexpr int kPreviewCount = 20; // ================= GLOBAL CONTROL ================= int active_threads = 0; int max_threads = 4; pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; std::mutex log_mutex; // ================= TIME ================= double get_time() { timeval tv{}; gettimeofday(&tv, nullptr); return tv.tv_sec + tv.tv_usec * 1e-6; } std::string now() { timeval tv{}; gettimeofday(&tv, nullptr); std::ostringstream oss; oss << tv.tv_sec << "." << std::setfill('0') << std::setw(6) << tv.tv_usec; return oss.str(); } // ================= SAFE LOGGING ================= void log_start(int l, int r, int depth) { std::lock_guard lock(log_mutex); std::cout << "START PID=" << getpid() << " TID=" << pthread_self() << " depth=" << depth << " range=[" << l << "," << r << "] time=" << now() << '\n'; } void log_end(int l, int r, int depth) { std::lock_guard lock(log_mutex); std::cout << "END PID=" << getpid() << " TID=" << pthread_self() << " depth=" << depth << " range=[" << l << "," << r << "] time=" << now() << '\n'; } // ================= MERGE ================= void merge_range(int* arr, int l, int m, int r) { std::vector tmp; tmp.reserve(r - l + 1); int i = l; int j = m + 1; while (i <= m && j <= r) { if (arr[i] <= arr[j]) tmp.push_back(arr[i++]); else tmp.push_back(arr[j++]); } while (i <= m) tmp.push_back(arr[i++]); while (j <= r) tmp.push_back(arr[j++]); std::copy(tmp.begin(), tmp.end(), arr + l); } // ================= LOCAL SORT ================= void local_sort(int* arr, int l, int r) { if (l >= r) return; int m = l + (r - l) / 2; local_sort(arr, l, m); local_sort(arr, m + 1, r); merge_range(arr, l, m, r); } // ================= THREAD ARG ================= struct Args { int* arr; int l; int r; int depth; }; void parallel_sort(int* arr, int l, int r, int depth); void* thread_func(void* arg) { Args* a = (Args*)arg; parallel_sort(a->arr, a->l, a->r, a->depth); delete a; return nullptr; } // ================= PARALLEL SORT ================= void parallel_sort(int* arr, int l, int r, int depth) { log_start(l, r, depth); if (l >= r) { log_end(l, r, depth); return; } int m = l + (r - l) / 2; pthread_t tid; bool spawned = false; // ===== thread limit control ===== pthread_mutex_lock(&thread_mutex); if (active_threads < max_threads) { active_threads++; spawned = true; } pthread_mutex_unlock(&thread_mutex); if (spawned) { Args* args = new Args{arr, m + 1, r, depth + 1}; pthread_create(&tid, nullptr, thread_func, args); parallel_sort(arr, l, m, depth + 1); pthread_join(tid, nullptr); pthread_mutex_lock(&thread_mutex); active_threads--; pthread_mutex_unlock(&thread_mutex); } else { parallel_sort(arr, l, m, depth + 1); parallel_sort(arr, m + 1, r, depth + 1); } merge_range(arr, l, m, r); log_end(l, r, depth); } // ================= UTIL ================= bool parse_int(const char* s, int& out) { try { size_t p; int v = std::stoi(s, &p); if (s[p] != '\0' || v < 0) return false; out = v; return true; } catch (...) { return false; } } // ================= MAIN ================= int main(int argc, char* argv[]) { int n = kDefaultN; if (argc >= 2 && !parse_int(argv[1], n)) { std::cerr << "Invalid N\n"; return 1; } if (argc >= 3 && !parse_int(argv[2], max_threads)) { std::cerr << "Invalid threads\n"; return 1; } std::vector arr(n); std::mt19937 rng(std::random_device{}()); std::uniform_int_distribution dist(0, 99999); for (int i = 0; i < n; i++) arr[i] = dist(rng); std::cout << "Before: "; for (int i = 0; i < std::min(n, kPreviewCount); i++) std::cout << arr[i] << " "; std::cout << "\n\n"; double t1 = get_time(); parallel_sort(arr.data(), 0, n - 1, 0); double t2 = get_time(); std::cout << "\nAfter: "; for (int i = 0; i < std::min(n, kPreviewCount); i++) std::cout << arr[i] << " "; std::cout << "\n"; std::cout << "\nTime: " << (t2 - t1) << " sec\n"; return 0; }