Files
OS-LABS/1/main.cpp
T
2026-04-28 14:55:14 +07:00

205 lines
5.6 KiB
C++

#include <iostream>
#include <vector>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <random>
#include <sstream>
#include <cmath>
constexpr int NIL = -1;
constexpr int MAX_PROCS = 1024; // Safety buffer for return values
struct Node {
int value;
int next;
};
struct SharedData {
int head;
int results[MAX_PROCS]; // Section for returning results in SHM
Node nodes[1];
};
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();
}
void log_start(int head, int depth) {
std::cout << "PROC_START pid=" << getpid()
<< " ppid=" << getppid()
<< " depth=" << depth
<< " l=" << head
<< " r=0"
<< " ts=" << now()
<< '\n' << std::flush;
}
void log_end(int head, int depth) {
std::cout << "PROC_END pid=" << getpid()
<< " ppid=" << getppid()
<< " depth=" << depth
<< " l=" << head
<< " r=0"
<< " ts=" << now()
<< '\n' << std::flush;
}
int merge_lists(Node* pool, int left_head, int right_head) {
if (left_head == NIL) return right_head;
if (right_head == NIL) return left_head;
int res_head = NIL;
int tail = NIL;
auto append = [&](int node_idx) {
if (res_head == NIL) {
res_head = node_idx;
tail = node_idx;
} else {
pool[tail].next = node_idx;
tail = node_idx;
}
};
while (left_head != NIL && right_head != NIL) {
if (pool[left_head].value <= pool[right_head].value) {
int next = pool[left_head].next;
append(left_head);
left_head = next;
} else {
int next = pool[right_head].next;
append(right_head);
right_head = next;
}
}
if (left_head != NIL) pool[tail].next = left_head;
if (right_head != NIL) pool[tail].next = right_head;
return res_head;
}
void split_list(Node* pool, int head, int& left, int& right) {
if (head == NIL || pool[head].next == NIL) {
left = head;
right = NIL;
return;
}
int slow = head;
int fast = pool[head].next;
while (fast != NIL) {
fast = pool[fast].next;
if (fast != NIL) {
slow = pool[slow].next;
fast = pool[fast].next;
}
}
left = head;
right = pool[slow].next;
pool[slow].next = NIL;
}
int local_list_sort(Node* pool, int head) {
if (head == NIL || pool[head].next == NIL) return head;
int left, right;
split_list(pool, head, left, right);
left = local_list_sort(pool, left);
right = local_list_sort(pool, right);
return merge_lists(pool, left, right);
}
// proc_idx helps each process find its unique slot in data->results
int parallel_list_sort(SharedData* data, int head, int depth, int max_depth, int proc_idx) {
log_start(head, depth);
if (head == NIL || data->nodes[head].next == NIL) {
log_end(head, depth);
return head;
}
if (depth >= max_depth) {
int result = local_list_sort(data->nodes, head);
log_end(result, depth);
return result;
}
int left_part, right_part;
split_list(data->nodes, head, left_part, right_part);
// Calculate unique IDs for children in the results array
int left_child_idx = 2 * proc_idx + 1;
int right_child_idx = 2 * proc_idx + 2;
pid_t pid_l = fork();
if (pid_l == 0) {
int res = parallel_list_sort(data, left_part, depth + 1, max_depth, left_child_idx);
data->results[left_child_idx] = res; // Return result in SHM
_exit(0);
}
pid_t pid_r = fork();
if (pid_r == 0) {
int res = parallel_list_sort(data, right_part, depth + 1, max_depth, right_child_idx);
data->results[right_child_idx] = res; // Return result in SHM
_exit(0);
}
// Synchronize: Parent waits for both children to finish writing to SHM
waitpid(pid_l, nullptr, 0);
waitpid(pid_r, nullptr, 0);
// Read results directly from Shared Memory
int sorted_l = data->results[left_child_idx];
int sorted_r = data->results[right_child_idx];
int final_head = merge_lists(data->nodes, sorted_l, sorted_r);
log_end(final_head, depth);
return final_head;
}
int main(int argc, char* argv[]) { //main(data count, max recursion level)
int n = 10000;
int max_depth = 3;
if (argc > 1) n = std::atoi(argv[1]);
if (argc > 2) max_depth = std::atoi(argv[2]);
size_t shm_size = sizeof(SharedData) + sizeof(Node) * (n - 1);
int shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0666);
SharedData* data = (SharedData*)shmat(shmid, nullptr, 0);
// Initialize return area
for(int i = 0; i < MAX_PROCS; ++i) data->results[i] = NIL;
data->head = 0;
std::mt19937 rng(time(0));
std::uniform_int_distribution<int> dist(0, 999);
for (int i = 0; i < n; ++i) {
data->nodes[i].value = dist(rng);
data->nodes[i].next = (i == n - 1) ? NIL : i + 1;
}
// Start with proc_idx 0 (the root)
data->head = parallel_list_sort(data, data->head, 0, max_depth, 0);
std::cout << "\nSorted list (first 20 elements): ";
int curr = data->head;
for(int i = 0; i < 20 && curr != NIL; ++i) {
std::cout << data->nodes[curr].value << " ";
curr = data->nodes[curr].next;
}
std::cout << std::endl;
shmdt(data);
shmctl(shmid, IPC_RMID, nullptr);
return 0;
}