多线程之多核线上考试试题瞎解

匆忙的大三早已结束,时隔两月,再以此文祭奠我炸掉的多核考试

这次考试真正能写出来的也就两道题,以下简单地记录一下。

第二题

随机产生2个10*10的浮点数矩阵A和B,先将矩阵A和B作转置,然后再相乘,请用windows 多线程函数方法和openMP方式分别编写实现上述运算的C语言并行实现程序,要求显示矩阵A和B,以及最终的运算结果。

题目涉及到矩阵转置和相乘两个主要内容,在编程时,我只对矩阵相乘进行openmp和多线程并行处理。

本题中,假设 A 、 B A、B AB均为 N × N N\times N N×N矩阵,令 C = A B C=AB C=AB,则矩阵 C C C i i i行第 j j j列原始可表示为:
C i j = ∑ k = 1 N a i k b k j = a i 1 b 1 j + a i 2 b 2 j + ⋯ + a i N b N j C_{ij}=\sum_{k=1}^Na_{ik}b_{kj}=a_{i1}b_{1j}+a_{i2}b_{2j}+\cdots +a_{iN}b_{Nj} Cij=k=1Naikbkj=ai1b1j+ai2b2j++aiNbNj
所以为了计算 A A A B B B相乘结果,需要三层循环,最内层计算 C C C中单个元素的值,第二层计算 C C C中单行元素的值,最外层计算整个矩阵 C C C的值。

为了减少线程开销,我们只对最外层循环进行并行处理,即每个线程计算一行相乘的结果。完整程序如下:

#include<thread>
#include<iostream>
#include<cstdlib>
#include "omp.h"
using namespace std;

#define N 10 // 矩阵维数

// 计算一行矩阵相乘结果的线程函数
void func(const double* a, const double* b, double* result, int i)
{
    // a:矩阵a的首地址
    // b:矩阵b的首地址
    // result:结果矩阵的第i行首地址
    // i:待计算的行号
	for (int j = 0; j < N; j++)
	{
		for (int k = 0; k < N; k++)
		{
			result[j] += a[i * N + k] * b[k * N + j];
		}
	}
}

int main()
{
	double a[N][N] = { {0} }; // 矩阵a
	double b[N][N] = { {0} }; // 矩阵b
	double result_omp[N][N] = { {0} }; // 保存openmp计算结果
	double result_multithread[N][N] = { {0} }; // 保存多线程计算结果
	// 产生随机双精度矩阵
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			a[i][j] = (double)(rand() % 100) / 100;
			b[i][j] = (double)(rand() % 100) / 100;
		}
	}

	// 打印转置前的矩阵a、b
	cout << "----------------------------" << endl;
	cout << "转置前a" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", a[i][j]);
		}
		cout << endl;
	}
	cout << "----------------------------" << endl;
	cout << "转置前b" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", b[i][j]);
		}
		cout << endl;
	}
	//--------- 转置 ---------
	for (int i = 0; i < N; i++)
	{
		for (int j = i; j < N; j++)
		{
			double at = a[i][j];
			double bt = b[i][j];
			a[i][j] = a[j][i];
			b[i][j] = b[j][i];
			a[j][i] = at;
			b[j][i] = bt;
		}
	}
	// 打印转置后的矩阵a、b
	cout << "----------------------------" << endl;
	cout << "转置后a" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", a[i][j]);
		}
		cout << endl;
	}
	cout << "----------------------------" << endl;
	cout << "转置后b" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", b[i][j]);
		}
		cout << endl;
	}

	//--------- 矩阵相乘 ---------
	// OMP方法
#pragma omp parallel for
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			for (int k = 0; k < N; k++)
				result_omp[i][j] += a[i][k] * b[k][j];
		}
	}

	// 多线程方法
	double* aa = a[0]; // 指向矩阵a首地址的指针
	double* bb = b[0]; // 指向矩阵b首地址的指针
	thread t[N];
	for (int i = 0; i < N; i++)
	{
		// 一个线程计算一行结果,共有N个线程
		t[i] = thread(func, aa, bb, result_multithread[i], i);
	}
	// 等待线程结束
	for (int i = 0; i < N; i++)
	{
		t[i].join();
	}

	// 打印OMP计算结果
	cout << "----------------------------" << endl;
	cout << "omp计算结果:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", result_omp[i][j]);
		}
		cout << endl;
	}
	// 打印多线程计算结果
	cout << "----------------------------" << endl;
	cout << "multi thread计算结果:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%5.3lf ", result_multithread[i][j]);
		}
		cout << endl;
	}

	return 0;
}

运行结果如下:

01

第三题

某停车场有100个停车位,共有3个入口,2个出口。剩余车位数量需要实时提供给各个出入口。请设计一个管理程序,要求使用多线程编程,每进入或驶出一辆车,在屏幕上输出当前空余的车位,如果没有剩余车位了,就要限制车辆进入该停车场。

这道题我感觉做复杂了,用到了C++11里的条件变量和互斥锁,设置两个条件变量,一个用于判断是否能够进入停车场,另一个用于判断是否能驶出停车场。

#include<thread>
#include<iostream>
#include<mutex>
#include<condition_variable>
using namespace std;

// 停车场的最大车位数量
#define PAKING_SPACE_MAX 100

// 入口数量
#define NUM_ENTER 3
// 出口数量
#define NUM_GO_OUT 2

// 线程中的循环次数,此时设置为100次
// 这样总共驶出次数为200次,进入次数为300次,最终停车场剩余车位应该为零
#define FOR_NUM 100 

int parkingspace = PAKING_SPACE_MAX; // 当前停车位数量
mutex m;
condition_variable cv1; // 进入操作的条件变量
condition_variable cv2; // 驶出操作的条件变量

// 车辆进入的线程函数
void t_enter(void)
{
    // 循环进入100辆车
    for (int i = 0; i < FOR_NUM; i++)
    {
        unique_lock<mutex> mylock(m);

        // 剩余车位数为0,表明停车场满了
        if (parkingspace <= 0)
            cv1.wait(mylock); // 不允许车进入,让他们在外面等
        parkingspace--;
        cout << "进入一辆车,剩余车位:" << parkingspace << endl;

        // 唤醒一个在等待中的线程,表示现在有车可以出去
        cv2.notify_one();
        // 延时100ms
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}
// 车辆驶出的线程函数
void t_go_out(void)
{
    // 循环驶出100辆车
    for (int i = 0; i < FOR_NUM; i++)
    {
        unique_lock<mutex> mylock(m);

        // 如果剩余车位数大于或者等于最大车位数量,则说明停车场是空的
        if (parkingspace >= PAKING_SPACE_MAX)
            cv2.wait(mylock); // 此时没有车辆,阻塞这个驶出线程
        parkingspace++;
        cout << "驶出一辆车,剩余车位:" << parkingspace << endl;

        // 唤醒一个在等待中的进入线程,表明有空车位,可以进入
        cv1.notify_one();
        // 延时100ms
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}
int main()
{
    thread t1[NUM_ENTER]; // 模拟三个入口
    thread t2[NUM_GO_OUT]; // 模拟两个出口

    /* 开启三个入口线程*/
    for (int i = 0; i < NUM_ENTER; i++)
    {
        t1[i] = thread(t_enter);
    }
    /* 开启两个出口线程 */
    for (int i = 0; i < NUM_GO_OUT; i++)
    {
        t2[i] = thread(t_go_out);
    }
    /* 等待所有入口线程执行完毕 */
    for (int i = 0; i < NUM_ENTER; i++)
    {
        t1[i].join();
    }
    /* 等待所有出口线程执行完毕 */
    for (int i = 0; i < NUM_GO_OUT; i++)
    {
        t2[i].join();
    }

}

结果如下:

02
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值