wip: 并行程序设计

This commit is contained in:
KirisameVanilla 2025-09-02 23:40:46 +08:00
parent 3889d1a3f6
commit 3436be625d
No known key found for this signature in database
GPG Key ID: 7FC750F817277AC5
26 changed files with 67 additions and 437 deletions

View File

@ -0,0 +1,50 @@
---
title: 2024-2025学年下学期期末
category:
- 软件工程学院
- 课程资料
tag:
- 试卷
author:
- タクヤマ
---
## 2025春季学期并行程序设计期末考试试卷回忆版
### 选择题
选择题都较简单, 不做记录.
### 填空题
1. 均匀储存访问模型中, 处理器访问储存器的时间\_\_\_\_, 物理储存器被所有处理器\_\_\_\_, 每台处理器带\_\_\_\_缓存.
2. MPI的点到点通信模式包括标准通信\_\_\_\_, \_\_\_\_, \_\_\_\_, \_\_\_\_.
3. 四种循环转换包括:循环交换, 循环分块, \_\_\_\_, \_\_\_\_.
4. MPI集合通信的三个主要功能是通信, \_\_\_\_, \_\_\_\_.
### 简答题
1. 简述 OpenMP 的 Fork-Join 工作模式.
2. 分布式内存系统与共享内存系统的核心区别是什么?
3. MPI阻塞接收与非阻塞接收的区别是什么?
4. 临界区嵌套会导致什么问题? 如何解决?
5. 简述信号量Semaphore实现 Barrier 的方法.
### 编程题
1. 哲学家用餐问题, 如何用互斥锁与信号量解决哲学家用餐问题, 保证不会出现死锁和饥饿? (注:此题只需写伪代码, 不需要严格的参照接口定义)
2. 多个进程分别拥有私有的数组, 现在要计算各个进程中所有数组元素的平均值.
使用MPI_Allreduce实现函数void Global_average(double loc_arr[], int loc_n, MPI_Comm comm, double* global_avg), 先计算局部总和与元素总数, 再归约计算全局总和与总元素数, 最后算平均值, 运行结束后所有进程中的global_avg都应该储存相同的结果, 即全局平均值.
其中loc_arr[]为每个进程拥有的局部数组, loc_n 为局部数组的大小, comm 为通讯器, global_avg 储存最终结果)
(注:本题下方提供了会用到的 MPI 函数定义以供查阅, 不需要特意背诵接口. 不过奇怪的是考试中唯独没有提供 MPI_Allreduce 的定义, 比较诡异)

View File

@ -1,39 +1,25 @@
# 2025春季学期并行程序设计期末考试试卷回忆版
---
title: 并行程序设计
category:
- 软件工程学院
- 课程评价
tag:
- 课程
---
## 选择题
## 2024-2025学年下学期
选择题都较简单,不做记录。
### 试卷
## 填空题
- [2024-2025学年下学期期末试卷](./2024-2025学年下学期期末.md)
1.均匀储存访问模型中,处理器访问储存器的时间\_\_\_\_物理储存器被所有处理器\_\_\_\_每台处理器带\_\_\_\_缓存。
### 谷守珍
2.MPI的点到点通信模式包括标准通信\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_。
#### 教学资源
3.四种循环转换包括:循环交换,循环分块,\_\_\_\_\_\_\_\_。
- [2024-2025学年下学期课件](https://drive.vanillaaaa.org/SharedCourses/软件工程学院/并行程序设计/2024-2025学年下学期/课件)
- [2024-2025学年下学期作业](https://drive.vanillaaaa.org/SharedCourses/软件工程学院/并行程序设计/2024-2025学年下学期/作业)
4.MPI集合通信的三个主要功能是通信\_\_\_\_\_\_\_\_。
## 推荐教材与参考资料
## 简答题
1.简述OpenMP的Fork-Join工作模式。
2.分布式内存系统与共享内存系统的核心区别是什么?
3.MPI阻塞接收与非阻塞接收的区别是什么
4.临界区嵌套会导致什么问题?如何解决?
5.简述信号量Semaphore实现Barrier的方法。
## 编程题
1.哲学家用餐问题,如何用互斥锁与信号量解决哲学家用餐问题,保证不会出现死锁和饥饿?(注:此题只需写伪代码,不需要严格的参照接口定义)
2.多个进程分别拥有私有的数组,现在要计算各个进程中所有数组元素的平均值。
使用MPI_Allreduce实现函数void Global_average(double loc_arr[], int loc_n, MPI_Comm comm, double* global_avg)先计算局部总和与元素总数再归约计算全局总和与总元素数最后算平均值运行结束后所有进程中的global_avg都应该储存相同的结果即全局平均值。
其中loc_arr[]为每个进程拥有的局部数组loc_n为局部数组的大小comm为通讯器global_avg储存最终结果
本题下方提供了会用到的MPI函数定义以供查阅不需要特意背诵接口。不过奇怪的是考试中唯独没有提供MPI_Allreduce的定义比较诡异
- [并行程序设计导论](https://drive.vanillaaaa.org/d/SharedCourses/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E5%B9%B6%E8%A1%8C%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1/%E5%B9%B6%E8%A1%8C%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E5%AF%BC%E8%AE%BA.pdf?sign=v1EtFro7aKJbuG-4kyKAiV3dQf6kRNag6o1QPUNm2to=:0)

View File

@ -1,21 +0,0 @@
Networked systems can be represented using graphs.
Tenants who use the systems in which their resources are
hosted need to check with the provider of the resources that
their resources are properly connected and that
their resources are properly separated from the resources of
other tenants. Since providers manage systems for
multiple tenants, a method to prove the connectivity and isolation
without revealing the network topology is required. As a solution,
an efficient zero-knowledge proof system of graph signatures
using a bilinear-map accumulator has been proposed, where the
verification time and the size of the proof data do not depend on
the number of graph vertexes and edges. However, this system
has two problems. First, since the proof does not include labels,
it is not possible to prove the connectivity considering network
bandwidth and cost. Second, since it assumes undirected graphs,
it cannot handle applications on directed graphs such as network
flows. In this study, we extend the previous system and propose
a zero-knowledge proof system of the connectivity for directed
graphs where each edge has labels. We implemented our system
on a PC using a pairng library and evaluate it by measuring the
processing times.

View File

@ -1,21 +0,0 @@
Networked systems can be represented using graphs.
Tenants who use the systems in which their resources are
hosted need to check with the provider of the resources that
their resources are properly connected and that
their resources are properly separated from the resources of
other tenants. Since providers manage systems for
multiple tenants, a method to prove the connectivity and isolation
without revealing the network topology is required. As a solution,
an efficient zero-knowledge proof system of graph signatures
using a bilinear-map accumulator has been proposed, where the
verification time and the size of the proof data do not depend on
the number of graph vertexes and edges. However, this system
has two problems. First, since the proof does not include labels,
it is not possible to prove the connectivity considering network
bandwidth and cost. Second, since it assumes undirected graphs,
it cannot handle applications on directed graphs such as network
flows. In this study, we extend the previous system and propose
a zero-knowledge proof system of the connectivity for directed
graphs where each edge has labels. We implemented our system
on a PC using a pairng library and evaluate it by measuring the
processing times.

View File

@ -1,21 +0,0 @@
Networked systems can be represented using graphs.
Tenants who use the systems in which their resources are
hosted need to check with the provider of the resources that
their resources are properly connected and that
their resources are properly separated from the resources of
other tenants. Since providers manage systems for
multiple tenants, a method to prove the connectivity and isolation
without revealing the network topology is required. As a solution,
an efficient zero-knowledge proof system of graph signatures
using a bilinear-map accumulator has been proposed, where the
verification time and the size of the proof data do not depend on
the number of graph vertexes and edges. However, this system
has two problems. First, since the proof does not include labels,
it is not possible to prove the connectivity considering network
bandwidth and cost. Second, since it assumes undirected graphs,
it cannot handle applications on directed graphs such as network
flows. In this study, we extend the previous system and propose
a zero-knowledge proof system of the connectivity for directed
graphs where each edge has labels. We implemented our system
on a PC using a pairng library and evaluate it by measuring the
processing times.

View File

@ -1,21 +0,0 @@
Networked systems can be represented using graphs.
Tenants who use the systems in which their resources are
hosted need to check with the provider of the resources that
their resources are properly connected and that
their resources are properly separated from the resources of
other tenants. Since providers manage systems for
multiple tenants, a method to prove the connectivity and isolation
without revealing the network topology is required. As a solution,
an efficient zero-knowledge proof system of graph signatures
using a bilinear-map accumulator has been proposed, where the
verification time and the size of the proof data do not depend on
the number of graph vertexes and edges. However, this system
has two problems. First, since the proof does not include labels,
it is not possible to prove the connectivity considering network
bandwidth and cost. Second, since it assumes undirected graphs,
it cannot handle applications on directed graphs such as network
flows. In this study, we extend the previous system and propose
a zero-knowledge proof system of the connectivity for directed
graphs where each edge has labels. We implemented our system
on a PC using a pairng library and evaluate it by measuring the
processing times.

View File

@ -1,111 +0,0 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <queue>
#include <omp.h>
#include <chrono>
#include <thread>
std::queue<std::string> shared_queue;
int producers_done = 0;
omp_lock_t queue_lock;
omp_lock_t output_lock;
int n;
void producer(int file_index, const char *filename)
{
std::ifstream file(filename);
if (!file.is_open())
{
#pragma omp critical
std::cerr << "Error opening file: " << filename << std::endl;
return;
}
std::string line;
while (std::getline(file, line))
{
omp_set_lock(&queue_lock);
shared_queue.push(line);
omp_unset_lock(&queue_lock);
}
omp_set_lock(&queue_lock);
producers_done++;
omp_unset_lock(&queue_lock);
}
void consumer()
{
while (true)
{
std::string line;
bool should_exit = false;
omp_set_lock(&queue_lock);
if (!shared_queue.empty())
{
line = shared_queue.front();
shared_queue.pop();
omp_unset_lock(&queue_lock);
std::istringstream iss(line);
std::string word;
while (iss >> word)
{
omp_set_lock(&output_lock);
std::cout << word << std::endl;
omp_unset_lock(&output_lock);
}
}
else
{
if (producers_done == n)
should_exit = true;
omp_unset_lock(&queue_lock);
if (should_exit)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
}
int main(int argc, char *argv[])
{
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " n file1 file2 ... filen" << std::endl;
return 1;
}
n = std::stoi(argv[1]);
if (argc != n + 2)
{
std::cerr << "Expected " << n << " files, got " << (argc - 2) << std::endl;
return 1;
}
omp_init_lock(&queue_lock);
omp_init_lock(&output_lock);
#pragma omp parallel num_threads(2 * n)
{
int tid = omp_get_thread_num();
if (tid < n)
{
producer(tid, argv[2 + tid]);
}
else
{
consumer();
}
}
omp_destroy_lock(&queue_lock);
omp_destroy_lock(&output_lock);
std::cout << std::endl
<< "All producers and consumers have finished." << std::endl;
return 0;
}
// g++ -o producer_consumer -fopenmp producer_consumer.cpp -std=c++11
// .\producer_consumer 4 1.txt 2.txt 3.txt 4.txt

View File

@ -1 +0,0 @@
请在本目录下,在终端输入 .\producer_consumer 4 1.txt 2.txt 3.txt 4.txt 以运行程序

View File

@ -1,162 +0,0 @@
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int compare(const void *a, const void *b)
{
return (*(int *)a - *(int *)b);
}
void merge(int *a, int *b, int *merged, int size)
{
int i = 0, j = 0, k = 0;
while (i < size && j < size)
{
if (a[i] < b[j])
{
merged[k++] = a[i++];
}
else
{
merged[k++] = b[j++];
}
}
while (i < size)
merged[k++] = a[i++];
while (j < size)
merged[k++] = b[j++];
}
int main(int argc, char **argv)
{
MPI_Init(&argc, &argv);
int my_rank, comm_sz;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
const int LOCAL_SIZE = 1250; // 共排序10000个元素用8个进程每个进程1250个元素
int *full_data = NULL;
if (my_rank == 0)
{
FILE *fp = fopen("input.txt", "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to open input file\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
int total_size = comm_sz * LOCAL_SIZE;
full_data = malloc(total_size * sizeof(int));
for (int i = 0; i < total_size; i++)
{
if (fscanf(fp, "%d", &full_data[i]) != 1)
{
fprintf(stderr, "Invalid input format\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
}
fclose(fp);
}
int *local_data = malloc(LOCAL_SIZE * sizeof(int));
if (local_data == NULL)
{
fprintf(stderr, "Memory allocation failed!\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
MPI_Scatter(full_data, LOCAL_SIZE, MPI_INT,
local_data, LOCAL_SIZE, MPI_INT,
0, MPI_COMM_WORLD);
// 本地排序
qsort(local_data, LOCAL_SIZE, sizeof(int), compare);
// 奇偶阶段排序
for (int phase = 0; phase < comm_sz; phase++)
{
int partner;
// 计算partner
if (phase % 2 == 0)
{
partner = my_rank + 1;
}
else
{
partner = my_rank - 1;
}
// 检查partner是否有效
if (partner < 0 || partner >= comm_sz)
{
continue;
}
// 准备发送和接收缓冲区
int *received_data = malloc(LOCAL_SIZE * sizeof(int));
int *merged_data = malloc(2 * LOCAL_SIZE * sizeof(int));
// 使用阻塞式通信交换数据
MPI_Sendrecv(local_data, LOCAL_SIZE, MPI_INT, partner, 0,
received_data, LOCAL_SIZE, MPI_INT, partner, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
// 合并两个有序数组
merge(local_data, received_data, merged_data, LOCAL_SIZE);
// 保留前一半或后一半
if (my_rank < partner)
{
// 保留较小的一半
for (int i = 0; i < LOCAL_SIZE; i++)
{
local_data[i] = merged_data[i];
}
}
else
{
// 保留较大的一半
for (int i = 0; i < LOCAL_SIZE; i++)
{
local_data[i] = merged_data[LOCAL_SIZE + i];
}
}
free(received_data);
free(merged_data);
}
// 排序完成后收集结果到0号进程
int *global_data = NULL;
if (my_rank == 0)
{
global_data = malloc(comm_sz * LOCAL_SIZE * sizeof(int));
}
MPI_Gather(local_data, LOCAL_SIZE, MPI_INT,
global_data, LOCAL_SIZE, MPI_INT,
0, MPI_COMM_WORLD);
if (my_rank == 0)
{
FILE *fout = fopen("output.txt", "w");
if (fout == NULL)
{
fprintf(stderr, "Failed to open output file\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
for (int i = 0; i < comm_sz * LOCAL_SIZE; i++)
{
fprintf(fout, "%d ", global_data[i]);
}
fprintf(fout, "\n");
fclose(fout);
}
free(local_data);
free(full_data);
free(global_data);
MPI_Finalize();
return 0;
}

View File

@ -1,7 +0,0 @@
# 作业说明
input.txt文件为无序的10000个数字输入到0号进程再分配到8个进程各排序1250个数字最后合并到0号进程输出到output.txt中
本目录下命令行运行:
1.mpicc mpi.c -o mpi
2.mpirun -np 8 ./mpi

View File

@ -1,39 +0,0 @@
# 2025春季学期并行程序设计期末考试试卷回忆版
## 选择题
选择题都较简单,不做记录。
## 填空题
1.均匀储存访问模型中,处理器访问储存器的时间\_\_\_\_物理储存器被所有处理器\_\_\_\_每台处理器带\_\_\_\_缓存。
2.MPI的点到点通信模式包括标准通信\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_。
3.四种循环转换包括:循环交换,循环分块,\_\_\_\_\_\_\_\_。
4.MPI集合通信的三个主要功能是通信\_\_\_\_\_\_\_\_。
## 简答题
1.简述OpenMP的Fork-Join工作模式。
2.分布式内存系统与共享内存系统的核心区别是什么?
3.MPI阻塞接收与非阻塞接收的区别是什么
4.临界区嵌套会导致什么问题?如何解决?
5.简述信号量Semaphore实现Barrier的方法。
## 编程题
1.哲学家用餐问题,如何用互斥锁与信号量解决哲学家用餐问题,保证不会出现死锁和饥饿?(注:此题只需写伪代码,不需要严格的参照接口定义)
2.多个进程分别拥有私有的数组,现在要计算各个进程中所有数组元素的平均值。
使用MPI_Allreduce实现函数void Global_average(double loc_arr[], int loc_n, MPI_Comm comm, double* global_avg)先计算局部总和与元素总数再归约计算全局总和与总元素数最后算平均值运行结束后所有进程中的global_avg都应该储存相同的结果即全局平均值。
其中loc_arr[]为每个进程拥有的局部数组loc_n为局部数组的大小comm为通讯器global_avg储存最终结果
本题下方提供了会用到的MPI函数定义以供查阅不需要特意背诵接口。不过奇怪的是考试中唯独没有提供MPI_Allreduce的定义比较诡异