197 lines
5.0 KiB
C++
197 lines
5.0 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>
|
|
|
|
constexpr int NIL = -1;
|
|
|
|
struct Node {
|
|
int value;
|
|
int next;
|
|
};
|
|
|
|
struct SharedData {
|
|
int head;
|
|
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);
|
|
}
|
|
|
|
int parallel_list_sort(Node* pool, int head, int depth, int max_depth) {
|
|
log_start(head, depth);
|
|
|
|
if (head == NIL || pool[head].next == NIL) {
|
|
log_end(head, depth);
|
|
return head;
|
|
}
|
|
|
|
if (depth >= max_depth) {
|
|
int result = local_list_sort(pool, head);
|
|
log_end(result, depth);
|
|
return result;
|
|
}
|
|
|
|
int left_part, right_part;
|
|
split_list(pool, head, left_part, right_part);
|
|
|
|
int pipe_l[2], pipe_r[2];
|
|
pipe(pipe_l);
|
|
pipe(pipe_r);
|
|
|
|
// Левый потомок
|
|
pid_t pid_l = fork();
|
|
if (pid_l == 0) {
|
|
close(pipe_l[0]); close(pipe_r[0]); close(pipe_r[1]);
|
|
int res = parallel_list_sort(pool, left_part, depth + 1, max_depth);
|
|
write(pipe_l[1], &res, sizeof(int));
|
|
close(pipe_l[1]);
|
|
_exit(0);
|
|
}
|
|
|
|
// Правый потомок
|
|
pid_t pid_r = fork();
|
|
if (pid_r == 0) {
|
|
close(pipe_r[0]); close(pipe_l[0]); close(pipe_l[1]);
|
|
int res = parallel_list_sort(pool, right_part, depth + 1, max_depth);
|
|
write(pipe_r[1], &res, sizeof(int));
|
|
close(pipe_r[1]);
|
|
_exit(0);
|
|
}
|
|
|
|
// Родитель ждет обоих
|
|
int sorted_l, sorted_r;
|
|
close(pipe_l[1]); close(pipe_r[1]);
|
|
|
|
waitpid(pid_l, nullptr, 0);
|
|
read(pipe_l[0], &sorted_l, sizeof(int));
|
|
|
|
waitpid(pid_r, nullptr, 0);
|
|
read(pipe_r[0], &sorted_r, sizeof(int));
|
|
|
|
close(pipe_l[0]); close(pipe_r[0]);
|
|
|
|
int final_head = merge_lists(pool, sorted_l, sorted_r);
|
|
log_end(final_head, depth);
|
|
return final_head;
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
int n = 1000;
|
|
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(int) + sizeof(Node) * n;
|
|
int shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0666);
|
|
SharedData* data = (SharedData*)shmat(shmid, nullptr, 0);
|
|
|
|
std::mt19937 rng(time(0));
|
|
std::uniform_int_distribution<int> dist(0, 9999);
|
|
for (int i = 0; i < n; ++i) {
|
|
data->nodes[i].value = dist(rng);
|
|
data->nodes[i].next = (i == n - 1) ? NIL : i + 1;
|
|
}
|
|
|
|
data->head = parallel_list_sort(data->nodes, data->head, 0, max_depth);
|
|
|
|
shmdt(data);
|
|
shmctl(shmid, IPC_RMID, nullptr);
|
|
return 0;
|
|
}
|