本代码主题借鉴nju的jyy老师的代码
自己增加了随机生成DAG(有向无环图)(不保证连通)数据进行测试
运行打印结果即为并行计算DAG的拓扑序
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
#define P(x) sem_wait(x)
#define V(x) sem_post(x)
const int N = 7;
struct Edge {
int from, to;
sem_t sem;
// 初始信号量值为0(使用c++标准库的信号量不能设置值为0)
Edge(int f, int t) : from(f), to(t) {
sem_init(&sem, 0, 0);
}
};
std::vector<Edge> edges;
/**
* 模拟计算任务
* 一格计算任务可能需要其它计算结点的计算结果,
* 又可能为其它计算结点提供自己的结果
*/
void* T_worker(void* arg) {
int id = *((int *)arg);
for (auto &edge : edges) {
if (edge.to == id) {
// id 为edge的入点
// 意味着id需要等这个edge的出点发出信号
P(&edge.sem);
}
}
printf("Start %d\n", id);
// 模拟计算过程
sleep(1);
printf("End %d\n", id);
for (auto &edge : edges) {
if (edge.from == id) {
// id是edge的出边, 表示id要释放这个边的信号量
V(&edge.sem);
}
}
}
/**
* 随机生成一个DAG
*/
void init_data() {
// 随机一个拓扑序
std::vector<int> vertices(N);
for (int i = 0; i < N; ++i) {
vertices[i] = i + 1;
}
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(vertices.begin(), vertices.end(), gen);
// 序号小的随机向序号大的结点连边
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
// 随机生成边
if (gen() % 3 == 0) {
edges.push_back(Edge(vertices[i], vertices[j]));
}
}
}
printf("graph:\n");
for (const auto& edge : edges) {
std::cout << edge.from << " -> " << edge.to << std::endl;
}
}
int main() {
std::vector<pthread_t> threads(N);
std::vector<int> pid(N);
init_data();
for (int i = 0; i < N; i++) {
pid[i] = i + 1;
pthread_create(&threads[i], nullptr, &T_worker, &pid[i]);
}
for (int i = 0; i < N; i++) {
pthread_join(threads[i], nullptr);
}
}