实习笔记Day12(2022.8.20)

一.总结

继续学习OpenMP基础函数和语法 

二.学习笔记 

(1)threadprivate子句的用法 

threadprivate子句可以将一个全局变量复制一个私有的拷贝给各个线程,即各个线程具有各自私有的全局对象。threadprivate和private的区别在于threadprivate声明的变量通常是全局范围内有效的,而private声明的变量只在它所属的并行构造中有效

#include <stdio.h>
#include <omp.h>

int g = 0;
#pragma omp threadprivate(g)

int main(int argc, char* argv[])
{
	int t = 20, i;
	#pragma omp parallel
	{
		g = omp_get_thread_num();
	}
	#pragma omp parallel
	{
		printf("thread id: %d g: %d\n", omp_get_thread_num(), g);
	}
	return 0;
}

运行结果(顺序可能不同)

thread id: 1 g: 1
thread id: 5 g: 5
thread id: 2 g: 2
thread id: 3 g: 3
thread id: 6 g: 6
thread id: 4 g: 4
thread id: 0 g: 0
thread id: 7 g: 7

(2)copyin子句的用法

copyin子句可以将主线程中变量的值拷贝到各个线程的私有变量中,让各个线程可以访问主线程中的变量。注意copyin的参数必须要被声明称threadprivate

#include <stdio.h>
#include <omp.h>

int g = 0;
#pragma omp threadprivate(g) 
int main(int argc, char* argv[])
{
	int i;
	#pragma omp parallel for   
	for (i = 0; i < 4; i++)
	{
		g = omp_get_thread_num();
		printf("thread %d, g = %d\n", omp_get_thread_num(), g);
	}
	printf("global g: %d\n", g);
	#pragma omp parallel for copyin(g)
	for (i = 0; i < 4; i++)
		printf("thread %d, g = %d\n", omp_get_thread_num(), g);
	return 0;
}

运行结果(顺序可能不同) 

thread 1, g = 1
thread 0, g = 0
thread 3, g = 3
thread 2, g = 2
global g: 0
thread 2, g = 0
thread 3, g = 0
thread 0, g = 0
thread 1, g = 0

可以看到,在使用copyin语句后,每个线程的g值都变成了0 

(3)static子句的用法 

当parallel for没有带schedule时,大部分情况下系统都会默认采用static调度方式。假设有n次循环迭代,t个线程,那么每个线程大约分到n/t次迭代。这种调度方式会将循环迭代均匀的分布给各个线程,各个线程迭代次数可能相差1次。用法为schedule(method) 

#pragma omp parallel for schedule(static)

(4)size参数的用法 

在不使用size参数时,分配给每个线程的是n/t次连续的迭代,若循环次数为10,线程数为2,则线程0得到了0~4次连续迭代,线程1得到5~9次连续迭代

当使用size时,将每次给线程分配size次迭代。若循环次数为10,线程数为2,指定size为2则0、1次迭代分配给线程0,2、3次迭代分配给线程1,以此类推

#pragma omp parallel for schedule(static,size)

(5)dynamic子句指令的用法 

动态调度依赖于运行时的状态动态确定线程所执行的迭代,也就是线程执行完已经分配的任务后,会去领取还有的任务(与静态调度最大的不同,每个线程完成的任务数量可能不一样)。由于线程启动和执行完的时间不确定,所以迭代被分配到哪个线程是无法事先知道的

当不使用size 时,是将迭代逐个地分配到各个线程。当使用size 时,逐个分配size个迭代给各个线程,这个用法类似静态调度

#pragma omp parallel for schedule(dynamic,size)

(6)omp_get_num_procs的用法 

返回调用函数时可用的处理器数目
函数原型

int omp_get_num_procs(void) 

(7)omp_get_num_threads的用法 

返回当前并行区域中的活动线程个数,如果在并行区域外部调用,返回1
函数原型

int omp_get_num_threads(void) 

(8)omp_get_thread_num的用法 

返回当前的线程号,注意不要和之前的omp_get_num_threads混淆。
函数原型

int omp_get_thread_num(void) 

(9)omp_set_num_threads的用法

设置进入并行区域时,将要创建的线程个数
函数原型

int omp_set_num_threads(void) 
#include <stdio.h>
#include <omp.h>

int main(int argc, char* argv[])
{
    omp_set_num_threads(4);
	#pragma omp parallel  
	{
		printf("%d of %d threads\n", omp_get_thread_num(), omp_get_num_threads());
	}
	return 0;
}

运行结果(顺序可能不同) 

0 of 4 threads
2 of 4 threads
1 of 4 threads
3 of 4 threads

(10)omp_in_parallel的用法

可以判断当前是否处于并行状态,是返回1,不是返回0
函数原型

int omp_in_parallel(); 

(11)omp_get_max_threads的用法 

该函数可以用于获得最大的线程数量,根据OpenMP文档中的规定,这个最大数量是指在不使用num_threads的情况下,OpenMP可以创建的最大线程数量。需要注意的是这个值是确定的,与它是否在并行区域调用没有关系

(12)OpenMP中互斥锁的用法 

Openmp中有提供一系列函数来进行锁的操作,一般来说常用的函数的下面4个

void omp_init_lock(omp_lock*) //初始化互斥锁
void omp_destroy_lock(omp_lock*) //销毁互斥锁
void omp_set_lock(omp_lock*) //获得互斥锁
void omp_unset_lock(omp_lock*) //释放互斥锁 
#include <stdio.h>
#include <omp.h>

static omp_lock_t lock;

int main(int argc, char* argv[])
{
    int i;
	omp_init_lock(&lock); 
	#pragma omp parallel for   
	for (i = 0; i < 5; ++i)
	{
		omp_set_lock(&lock);
		printf("%d+\n", omp_get_thread_num());
		printf("%d-\n", omp_get_thread_num());
		omp_unset_lock(&lock); 
	}
	omp_destroy_lock(&lock);
	return 0;
}

运行结果(每个数字顺序可能不同,但每一个数字的正负一定是挨着输出的)

1+
1-
4+
4-
0+
0-
2+
2-
3+
3-

(13)omp_test_lock的用法 

除了之前介绍的4个函数之外,与互斥锁的相关的函数还有一个,用来尝试获得锁
该函数可以看作是omp_set_lock的非阻塞版本
函数原型

bool omp_test_lock(omp_lock*) 
#include <stdio.h>
#include <omp.h>

static omp_lock_t lock;

int main(int argc, char* argv[])
{
    int i;
	omp_init_lock(&lock); 
	#pragma omp parallel for   
	for (i = 0; i < 5; ++i)
	{
		if (omp_test_lock(&lock))
		{
			printf("%d+\n", omp_get_thread_num());
			printf("%d-\n", omp_get_thread_num());
			omp_unset_lock(&lock);
		}
		else
		{
			printf("fail to get lock\n");
		}
	}
	omp_destroy_lock(&lock);
	return 0;
}

运行结果(可能不同)

1+
1-
fail to get lock
4+
4-
fail to get lock
fail to get lock

(14)omp_set_dynamic的用法 

该函数可以设置是否允许在运行时动态调整并行区域的线程
函数原型

void omp_set_dynamic(int)

当参数为0时,动态调整被禁用
当参数为非0值时,系统会自动调整线程以最佳利用系统资源

(15)omp_get_dynamic的用法 

该函数可以查看当前程序是否允许在运行时动态调整并行区域的线程

当返回值为非0时表示允许系统动态调整线程
当返回值为0时表示不允许
函数原型

int omp_get_dynamic()

三.工作记录 

暂无

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值