wip: 并行程序设计
This commit is contained in:
parent
920d79b4a6
commit
24798d2fa8
|
|
@ -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 的定义, 比较诡异)
|
||||||
|
|
@ -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集合通信的三个主要功能是:通信,\_\_\_\_,\_\_\_\_。
|
## 推荐教材与参考资料
|
||||||
|
|
||||||
## 简答题
|
- [并行程序设计导论](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)
|
||||||
|
|
||||||
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的定义,比较诡异)
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
请在本目录下,在终端输入 .\producer_consumer 4 1.txt 2.txt 3.txt 4.txt 以运行程序
|
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -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;
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +0,0 @@
|
||||||
# 作业说明
|
|
||||||
|
|
||||||
input.txt文件为无序的10000个数字,输入到0号进程,再分配到8个进程,各排序1250个数字,最后合并到0号进程输出到output.txt中
|
|
||||||
|
|
||||||
本目录下命令行运行:
|
|
||||||
1.mpicc mpi.c -o mpi
|
|
||||||
2.mpirun -np 8 ./mpi
|
|
||||||
|
|
@ -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的定义,比较诡异)
|
|
||||||
Loading…
Reference in New Issue