并行计算-OPENMP(windows)

         并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算。并行计算系统既可以是专门设计的、含有多个处理器的超级计算机,也可以是以某种方式互连的若干台的独立计算机构成的集群。通过并行计算集群完成数据的处理,再将处理的结果返回给用户。

        OpenMP是由OpenMP Architecture Review Board牵头提出的,用于共享内存并行系统的多处理器程序设计的一套指导性编译处理方案。OpenMP支持的编程语言包括C、C++和Fortran。OpenMp提供了对并行算法的高层的抽象描述,程序员通过在源代码中加入专用的pragma来指明自己的意图,由此编译器可以自动将程序进行并行化,并在必要之处加入同步互斥以及通信。当选择忽略这些pragma,或者编译器不支持OpenMp时,程序又可退化为通常的程序(一般为串行),代码仍然可以正常运作,只是不能利用多线程来加速程序执行。

        在VS中使用OPENMP需要打开Open MP支持开关,如下图VS2019中打开方式。

 Hello, omp! 如下代码会根据运行机器上的处理器开对应数量的线程进行运行。

#include <iostream>
#include <omp.h>
using namespace std;
#include <windows.h>
int main()
{
#pragma omp parallel
    {
        DWORD dwThread = GetCurrentThreadId();
        printf("ThreadID:%d  threadIndex:%d, Hello, omp!\r\n", \
            dwThread, omp_get_thread_num());
    }
    system("pause");
}

Open MP函数

函数名

函数 功能说明

omp_set_num_threads

设置即将出现的并行区域中的线程数,除非由 num_threads 子句重写。

omp_get_num_threads

返回并行区域中的线程数。

omp_get_max_threads

如果在代码中的该位置定义了没有 num_threads 的并行区域,则返回等于或大于可用线程数的整数。

omp_get_thread_num

返回在其线程组中执行的线程的线程编号。

omp_get_num_procs

返回调用函数时可用的处理器数。

omp_in_parallel

如果从并行区域内调用,则返回非零值。

omp_set_nested

启用或者禁用嵌套并行。

omp_get_nested

判断嵌套并行是否启用。

锁相关函数

函数名

函数功能说明

omp_init_lock

初始化锁

omp_destroy_lock

取消初始化锁

omp_set_lock

阻塞线程执行,直到锁可用

omp_unset_lock

释放锁

omp_test_lock

尝试设置锁但不阻塞线程执行

Open MP指令

函数名

函数功能说明

omp_init_lock

初始化锁

omp_destroy_lock

取消初始化锁

omp_set_lock

阻塞线程执行,直到锁可用

omp_unset_lock

释放锁

omp_test_lock

尝试设置锁但不阻塞线程执行

#include <iostream>
#include <omp.h>
using namespace std;
#include <windows.h>

void OMPTestAPI()
{
    int max_threads = omp_get_max_threads();
    int num_threads = omp_get_num_threads();
    int num_procs = omp_get_num_procs();


    printf("Max threads: %d\n", max_threads);
    printf("Num threads: %d\n", num_threads);
    printf("Num Procs:%d\n", num_procs);
    omp_set_num_threads(6);
    int nInparallel = omp_in_parallel();
    printf("Inparallel:%d\n", nInparallel);

#pragma omp parallel
    {
        nInparallel = omp_in_parallel();
        printf("Inparallel:%d\n", nInparallel);
        num_threads = omp_get_num_threads();
        int thread_id = omp_get_thread_num();
        printf("Thread ID: %d, maxthread num:%d\n", thread_id, max_threads);
    }
}

int nest_test() {
    int nNest = omp_get_nested();
    printf("Nest state:%d\n", nNest);
    omp_set_nested(1);  // 启用嵌套并行

#pragma omp parallel num_threads(2)
    {
        printf("Outer parallel region\n");

        nNest = omp_get_nested();
        printf("After SetNest Nest state:%d\n", nNest);
#pragma omp parallel num_threads(2)
        {
            printf("Inner parallel region\n");
        }
    }
}

void atomic_Cmd()
{
    int count = 0;
#pragma omp parallel num_threads(10)
    {
#pragma omp atomic
        count++;
    }
    printf_s("Number of threads: %d\n", count);
}

void for_Cmd()
{
    int count = 0;
    omp_set_num_threads(2);
    
    //并行for
#pragma omp parallel
#pragma omp  for
//#pragma omp parallel for
    for (int i = 0; i < 4; i++)
    {
        ++count;
        printf_s("Thread num:%d, count:%d\r\n", omp_get_thread_num(), count);
    }
    
    //普通 for
    count = 0;
    for (int i = 0; i < 4; i++)
    {
        ++count;
        printf_s("ThreadID:%d, count:%d\r\n", GetCurrentThreadId(), count);
    }
}

void master_Cmd()
{
    DWORD dwThreadID = GetCurrentThreadId();
    printf("main thread id is %d\r\n", dwThreadID);
#pragma omp parallel num_threads(3)
    {
        printf("Hello from thread %d\n", omp_get_thread_num());
#pragma omp master
        {
            printf("Hello from master thread %d, threadid:%d\n", omp_get_thread_num(), GetCurrentThreadId());
            // 只有主线程执行下面的代码
            // 执行一些仅需执行一次的工作
        }
    }
}

void barrier_Cmd()
{
#pragma omp parallel num_threads(4)
    {
        printf("Hello from thread %d\n", omp_get_thread_num());
        
        //等待
#pragma omp barrier
        printf("World from thread %d\n", omp_get_thread_num());
    }
}

void critical_Cmd()
{
    int shared_var = 0;

#pragma omp parallel num_threads(4)
    {
        int thread_num = omp_get_thread_num();
        printf("Thread %d is executing before the critical section\n", thread_num);

#pragma omp critical
        {
            // 进入临界区代码块
            printf("Thread %d is inside the critical section\n", thread_num);
            shared_var++;
            printf("Shared variable incremented by Thread %d: %d\n", thread_num, shared_var);
            // 退出临界区代码块
        }

        printf("Thread %d is executing after the critical section\n", thread_num);
    }
}

void flush_Cmd()
{
    int shared_var = 0;

#pragma omp parallel num_threads(20)
    {
#pragma omp critical
        {
            // 对共享变量进行修改
            shared_var++;
            printf("Thread %d: shared_var = %d\n", omp_get_thread_num(), shared_var);
        }

        // 执行 flush 操作以确保共享变量的修改对所有线程可见
//#pragma omp flush

// 访问共享变量
        printf("Thread %d: shared_var = %d\n", omp_get_thread_num(), shared_var);
    }

//    int shared_var = 0;
//
//#pragma omp parallel num_threads(2)
//    {
//        int thread_num = omp_get_thread_num();
//
//        if (thread_num == 0) {
//            // 线程0写入共享变量(写入操作1)
//            shared_var = 42;
#pragma omp flush(shared_var)
//            // 写入操作1完成后,强制刷新到主存,使其对其他线程可见
//        }
//
//#pragma omp barrier
//
//        if (thread_num == 1) {
//            // 线程1读取共享变量(读取操作1)
//            // 在读取之前,需要使用 flush 指令确保对 shared_var 的最新写入全部对线程1可见
//#//pragma omp flush(shared_var)
//
//            printf("Thread %d reads shared_var: %d\n", thread_num, shared_var);
//        }
//    }

}

void ordered_Cmd()
{
#pragma omp parallel num_threads(5)
    {
        int thread_num = omp_get_thread_num();
#pragma omp for ordered
        for (int i = 0; i < 4; i++) {
#pragma omp ordered
            {
                printf("Thread %d is executing iteration %d\n", thread_num, i);
            }
        }
    }
}

void section_Cmd()
{
#pragma omp parallel num_threads(4)
    {
#pragma omp sections
        {
#pragma omp section
            {
                printf("This is Section 1, executed by Thread %d\n", omp_get_thread_num());
            }

#pragma omp section
            {
                printf("This is Section 2, executed by Thread %d\n", omp_get_thread_num());
            }

#pragma omp section
            {
                printf("This is Section 3, executed by Thread %d\n", omp_get_thread_num());
            }
        }
    }


//#pragma omp parallel sections num_threads(4)
//    {
//        printf_s("Hello from thread %d\n", omp_get_thread_num());
//#pragma omp section
//        printf_s("Hello from thread %d\n", omp_get_thread_num());
//    }
}

void single_Cmd()
{
#pragma omp parallel num_threads(4)
    {
#pragma omp single
        {
            printf("This is executed by Thread %d\n", omp_get_thread_num());
        }
    }
}
int nx = 0; // 全局变量x
#pragma omp threadprivate(nx)

int g = 2;

#pragma omp threadprivate(g)  

void threadprivate_Cmd()
{
    /* Explicitly turn off dynamic threads */
    //omp_set_dynamic(0);
    DWORD dwID = GetCurrentThreadId();
    printf("start g:%d, ThreadID:%d\r\n", g, dwID);
    printf("Masterthread started\n\n");
    
#pragma omp parallel 
    {
        dwID = GetCurrentThreadId();
        g = omp_get_thread_num();
        printf("tid: %d, Theadid:%d\n", g, dwID);
    } // End of parallel region  
    printf("mid g:%d\r\n", g);
#pragma omp parallel  
    {
        int temp = g * g+1;
        printf("tid : %d, tid*tid: %d\n", g, temp);
    } // End of parallel region  

    printf("Masterthread finished\n");
    printf("end g:%d\r\n", g);
}


omp_lock_t simple_lock;

int Lock_test () {
    omp_init_lock(&simple_lock);

#pragma omp parallel num_threads(4)
    {
        int tid = omp_get_thread_num();

        while (!omp_test_lock(&simple_lock))
            printf_s("Thread %d - failed to acquire simple_lock\n",
                tid);

        printf_s("Thread %d - acquired simple_lock\n", tid);

        printf_s("Thread %d - released simple_lock\n", tid);
        omp_unset_lock(&simple_lock);
    }

    omp_destroy_lock(&simple_lock);
}

参考资料:

https://learn.microsoft.com/zh-cn/cpp/parallel/openmp/reference/openmp-environment-variables?view=msvc-170

https://blog.csdn.net/lovely_yoshino/article/details/127688670

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/46247.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud学习路线(12)——分布式搜索ElasticSeach数据聚合、自动补全、数据同步

一、数据聚合 聚合&#xff08;aggregations&#xff09;&#xff1a; 实现对文档数据的统计、分析、运算。 &#xff08;一&#xff09;聚合的常见种类 桶&#xff08;Bucket&#xff09;聚合&#xff1a; 用来做文档分组。 TermAggregation&#xff1a; 按照文档字段值分组…

AWS / VPC 云流量监控

由于安全性、数据现代化、增长、灵活性和成本等原因促使更多企业迁移到云&#xff0c;将数据存储在本地的组织正在使用云来存储其重要数据。亚马逊网络服务&#xff08;AWS&#xff09;仍然是最受追捧和需求的服务之一&#xff0c;而亚马逊虚拟私有云&#xff08;VPC&#xff0…

flutter android Webview 打开网页错误ERR_CLEARTEXT_NOT_PERMITTED 、 net:ERR_CACHE_MISS

当你在Flutter应用中尝试打开一个非安全连接的网页&#xff08;例如HTTP连接而不是HTTPS连接&#xff09;时&#xff0c;可能会遇到"ERR_CLEARTEXT_NOT_PERMITTED"错误。这是因为默认情况下&#xff0c;Android 9及更高版本禁止应用程序通过非安全的明文HTTP连接进行…

5-linux中的定时任务调度

定时任务调度 crond 任务调度概述基本语法常用选项快速入门应用实例crond 相关指令 at 定时任务基本介绍at 命令格式at 命令选项at 时间的定义其他指令 crond 任务调度 crontab 进行 定时任务调度 概述 任务调度&#xff1a;是指系统在某个时间执行的特定的命令或程序 任务…

JVM运行时数据区——字符串常量池位置的调整

在JDK6及之前&#xff0c;使用永久代来实现方法区&#xff0c;字符串常量池(StringTable)是在永久代(方法区)中的&#xff0c;但是方法区的回收效率不高&#xff0c;在Full GC时才会回收。 在JDK7中&#xff0c;将字符串常量池转移到了堆中&#xff0c;分配在年轻代和老年代中。…

C++模板的简单练习

运行代码&#xff1a; #include"std_lib_facilities.h"template <class T>struct S { private:T val; public:S<T>() :val(T()) {}S<T>(T tt) : val(tt) {};T& get();void set(T tt) { val tt; }ostream& operator << (ostream&a…

电脑记事本在哪里?电脑桌面显示记事本要怎么设置?

绝大多数上班族在使用电脑办公时&#xff0c;都需要随手记录一些琐碎或重要的事情&#xff0c;例如工作注意事项、常用的文案、某项工作的具体要求、多个平台的账号和密码等。于是就有不少小伙伴想要使用电脑记事本软件来记录&#xff0c;那么电脑记事本在哪里呢&#xff1f;想…

MySQL数据库关于表的一系列操作

MySQL中的数据类型 varchar 动态字符串类型&#xff08;最长255位&#xff09;&#xff0c;可以根据实际长度来动态分配空间&#xff0c;例如&#xff1a;varchar(100) char 定长字符串&#xff08;最长255位&#xff09;&#xff0c;存储空间是固定的&#xff0c;例如&#…

【大虾送书第三期】《Python高并发与高性能编程: 原理与实践》

目录 ✨写在前面 ✨主要内容 ✨本书特色 ✨关于作者 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &#x1f990;专栏地址&#xff1a;免费送书活动专栏地址 写在前面 Python成为时下技术革新的弄潮儿&#xff0c;全民Python的发展趋势让人们不再满足于简单地运行Python…

LeetCode三步问题(动态规划)

LeetCode三步问题&#xff08;动态规划&#xff09; 编写代码代码优化 链接: 三步问题 编写代码 class Solution { public:int waysToStep(int n) {if(n 1 || n 2) return n;vector<int> dp(n1);const int MOD 1e9 7;dp[0] dp[1] 1;dp[2] 2;for(int i 3;i<n…

白话机器学习笔记(一)学习回归

最小二乘法 定义模型 表达式&#xff1a; f θ ( x ) θ 0 θ 1 x f_\theta(x)\theta_0\theta_1x fθ​(x)θ0​θ1​x &#xff08;常用 θ \theta θ表示未知数、 f θ ( x ) f_\theta(x) fθ​(x)表示含有参数 θ \theta θ并且和变量 x x x相关的函数&#xff09; 目标…

Vue中TodoLists案例_底部统计

与上一篇Vue中TodoList案例_删除有俩个文件变化了 App.vue&#xff1a;向儿子组件MyFooter传递参数todos <template><div id"root"><div class"todo-container"><div class"todo-wrap"><MyHeader :addTodo"add…

Qt 第一讲

登录框设置 #include "zuoye.h" #include "ui_zuoye.h"Zuoye::Zuoye(QWidget *parent): QWidget(parent), ui(new Ui::Zuoye) {ui->setupUi(this);//界面this->resize(540,420); //设置尺寸this->setFixedSize(540,420);//固定尺寸this->setS…

Spring 创建和使用

Spring 是⼀个包含了众多⼯具⽅法的 IoC 容器。既然是容器那么它就具备两个最基本的功能&#xff1a; 将对象存储到容器&#xff08;Spring&#xff09;中&#xff1b; 从容器中将对象取出来。 在 Java 语⾔中对象也叫做 Bean 1.创建 Spring 项目 接下来使⽤ Maven ⽅式来创…

智慧景区综合解决方案52页,多媒体触控系统,顶层设计

导读&#xff1a;原文《智慧景区综合解决方案52页ppt》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式&#xff1a; 如需获取完整的电…

Python面向对象(三)(继承、封装)

面向对象的三大特性 面向对象编程&#xff0c;是许多编程语言都支持的一种编程思想。 简单理解是&#xff1a;基于模板&#xff08;类&#xff09;去创建实体&#xff08;对象&#xff09;&#xff0c;使用对象完成功能开发。 面向对象包含3大主要特性&#xff1a; 封装 封…

静态 链接

1、空间与地址的分配 现在的链接器空间分配的策略基本上都采用 “相似段合并” 的方式。通过将所有相同类型的 section 合并到一起&#xff0c;例如将所有输入目标文件的 .text 合并&#xff08;按顺序合并&#xff09;到输出文件的 .text 节中&#xff1b;然后&#xff0c;链接…

机器学习之线性判别分析(Linear Discriminant Analysis)

1 线性判别分析介绍 1.1 什么是线性判别分析 线性判别分析&#xff08;Linear Discriminant Analysis&#xff0c;简称LDA&#xff09;是一种经典的监督学习算法&#xff0c;也称"Fisher 判别分析"。LDA在模式识别领域&#xff08;比如人脸识别&#xff0c;舰艇识别…

链表踏歌:独具慧眼,雕琢重复元素藏身匿迹

本篇博客会讲解力扣“83. 删除排序链表中的重复元素”的解题思路&#xff0c;这是题目链接。 由于链表是排好序的&#xff0c;我们可以通过遍历一次链表的方式&#xff0c;删除所有重复的结点。具体来说&#xff0c; 如果链表为空&#xff0c;则不需要删除&#xff0c;直接返回…

全加器(多位)的实现

一&#xff0c;半加器 定义 半加器&#xff08;Half Adder&#xff09;是一种用于执行二进制数相加的简单逻辑电路。它可以将两个输入位的和&#xff08;Sum&#xff09;和进位&#xff08;Carry&#xff09;计算出来。 半加器有两个输入&#xff1a;A 和 B&#xff0c;分别代表…
最新文章